2011-08-12 9 views
2

私はいくつかの例を試していましたが、プロトタイプに関数を追加したい場合、コンストラクタのプライベートメンバーにアクセスすることができないという問題がありました。私はthis解決策を見つけました。これはいいハックだと思われる。コンストラクタ関数内のプロトタイプへのプロパティの追加

私はいくつかの他の方法を試して、私は次のようだ:我々はコンストラクタ関数内のプロトタイプに追加しているので

var Restaurant = function() 
{ 
    var myPrivateVar; 
    var private_stuff = function() // Only visible inside Restaurant() 
    { 
     return "I can set this here!"; 
    } 
    Restaurant.prototype.use_restroom = function() // use_restroom is visible to all 
    { 
     private_stuff(); 
    } 
    Restaurant.prototype.buy_food = function() // buy_food is visible to all 
    { 
     return private_stuff(); 
    } 
} 
var restaurant = new Restaurant(); 
restaurant.buy_food(); // this would work 
restaurant.private_stuff(); // this won't 

ソリューションは奇妙なようです。 (私はこれをほとんど見ていない)。これは少なくともfirefox 5とchromeで動作します。何か問題がありますか?

答えて

11

あなたはプロトタイプでこれらのメソッドあなたが作るたびに再定義されてやっています新しいレストランオブジェクト。それを行うには、より健全な方法は、新しいオブジェクトはコンストラクタで構築されている、thisでそれらを定義するには、次のようになります。

var Restaurant = function() 
{ 
    var myPrivateVar; 
    var private_stuff = function() // Only visible inside Restaurant() 
    { 
     return "I can set this here!"; 
    } 
    this.use_restroom = function() // use_restroom is visible to all 
    { 
     private_stuff(); 
    } 
    this.buy_food = function() // buy_food is visible to all 
    { 
     return private_stuff(); 
    } 
} 

あなたはしかし、このようにそれを行うだけで、そして使用することができませんでしnew

var RestaurantMaker = function() { 
    var myPrivateVar; 
    var private_stuff = function() { 
    return "I can set this here!"; 
    } 

    return { 
    use_restroom: function() { 
     private_stuff(); 
    }, 
    buy_food: function() { 
     return private_stuff(); 
    } 
    }; 
} 

、その後はちょうど行います

var restaurant = RestaurantMaker(); 

これは、暴露のモジュールパターンと呼ばれています。欠点は、新しいオブジェクトごとにすべての関数のコピーが得られることです。コンストラクタ内のメソッドをthisに追加した場合にも発生します。

暴露のモジュールパターンの非常に小さな代替バージョンでは、(私は少し良く読みだと思うもの)次のようになります。そして、

var RestaurantMaker = function() { 
    var myPrivateVar; 

    function private_stuff() { 
    return "I can set this here!"; 
    } 

    function use_restroom() { 
    private_stuff(); 
    } 

    function buy_food() { 
    return private_stuff(); 
    } 

    return { 
    use_restroom: use_restroom, 
    buy_food: buy_food 
    }; 
} 

、あなたは関数がプライベートであるかどうかを変更したい場合は、それはです返されたオブジェクトに追加または削除するだけです。

+1

ですばらしい説明とコメントをくれたことで、それを修正しました。オブジェクトを作成するたびに、プロトタイプのメソッドを再定義しているという点は全く分かりませんでした。以前はモジュラーパターンを見ていました。しかし、私が直面していた問題は、私が 'restaurantMaker'を呼び出すたびに、' use_restroom'と 'buy_food'の新しいインスタンスを取得するということでした。これは必要ではない。すなわち、プロトタイプに追加することができれば共有されている可能性がある。 –

+0

問題は、関数がプライベート変数と同じスコープで定義されている場合にのみ、関数がプライベート変数にアクセスできることです。したがって、関数を一度しか定義していない場合、関数はすべて同じプライベート変数を共有するか、アクセスできません。あなたがレストランのオブジェクトの100sを持っているならば、それは本当に問題です。 – Skilldrick

2

私は実際にこれをテストしませんでしたが、私はすべてのオブジェクトが最後にインスタンス化されたオブジェクトのプライベートプロパティにアクセスすると思います。あなたがオブジェクトのプライベート変数をインスタンス化している:)

2

を正直に(すべてのインスタンス間で共有)プロトタイプのメソッドを結合している各インスタンス化で

、それは私に多くの意味がありません。もちろん、プライベート関数をこのように呼び出すことはできますが、初期の問題は解決しません。つまり、コンストラクタ内にメソッドを追加する必要があります。あなたは、コンストラクタの外のクラスにメソッドを追加したい場合は

、あなたはきれいなコンストラクタを保つためにクロージャを使用することができます。

// Creating a closure inside a self-calling function 
var Restaurant = (function() { 

    // Only visible inside this closure 
    var myPrivateVar; 
    var private_stuff = function() { 
     return "I can set this here!"; 
    } 

    var Restaurant = function() {}; 

    // use_restroom is visible to all 
    Restaurant.prototype.use_restroom = function() { 
     private_stuff(); 
    }; 

    // buy_food is visible to all 
    Restaurant.prototype.buy_food = function() { 
     return private_stuff(); 
    }; 

    // We give back the Restaurant-constructor to the people 
    return Restaurant; 

})(); 

var restaurant = new Restaurant(); 
restaurant.buy_food(); // this would work 
restaurant.private_stuff(); // this won't 
+1

代わりのグローバルスコープで 'Restaurant'を定義し、それへの割り当てを、あなただけの'閉鎖内部window.Restaurant'を言うことができます。 – Skilldrick

+0

はい、そうです、それは自己呼び出し関数から返される可能性もあるので、変数に代入することができます。 –

+2

ここでの問題は、レストランのすべてのインスタンスが同じ 'privateVar'を共有するということです。これはOPの後にあったかもしれません。 – Skilldrick

0

私たちは別のアプローチをとっています。クラスレベルで状態を管理する必要がある場合にのみ、クロージャを使用することがあります。スコープを管理するために名前空間を使用します。プロトタイプのメソッドを持つ単純なクラスのために、私達はちょうどこの操作を行います。

/** 
* @namespace 
*/ 
var chain = {}; 

(function() { 

    /** 
    * The constructor is used to manage private data 
    * @constructor 
    */ 
    chain.Restaurant = function() { 
     // Only visible inside this constructor 
     var inventory = { }; 

     /** 
     * add an item with a count to the inventory 
     * This is a privileged function. 
     * @param {String} item The identifier for the item you are adding 
     * @param {String} count The count you are adding for the item. 
     */ 
     this.addInventory = function (item, count) { 
      if (count < 0) { 
       // throw an error 
      } 
      var current = this.getInventory(item); 
      inventory[item] = current + count; 
     } 

     // privileged function 
     this.getInventory = function (item) { 
      if (inventory.hasOwnProperty(item)) { 
       return inventory[item]; 
      } 
      return 0; 
     } 

     // privileged function 
     this.removeInventory = function (item, count) { 
      throwIfNegative(count); 
      if (this.getInventory(item) < count) { 
       throw new Error("Inventory Unavailable"); 
      } 
      inventory[item] -= count; 
     } 

     // private function, only visible to the privileged functions 
     function throwIfNegative (value) { 
      if (value < 0) { 
       throw new Error("Negative Inventory Is Not Valid"); 
      } 
     } 
    } 

    // member/prototype method 
    chain.Restaurant.prototype.sellInventory = function (item, count) { 
     var availabe = this.getInventory(item); 
     var sellCount = Math.min(available, count, 0); 
     if (sellCount > 0) { 
      // do this conditionally if there are implications to invoking the functions 
      this.removeInventory(sellCount); 
      sellItem(item, sellCount); 
     } 
     return sellCount; 
    } 

    // member/prototype method 
    chain.Restaurant.prototype.hasInventory = function (item, count) { 
     return this.getInventory(item) >= count; 
    } 

    // member/prototype method 
    chain.soldQuantity = function (item) { 
     if (!itemsSold.hasOwnProperty(item)) { 
      return 0; 
     } 
     return itemsSold[item]; 
    } 

    // functions defined in this closure can see this 
    var itemsSold = { }; 

    // all functions defined in this closer can call this 
    function sellItem (item, quantity) { 
     if (!itemsSold.hasOwnProperty(item)) { 
      itemsSold[item] = 0; 
     } 
     itemsSold[item] += quantity; 
    } 
})(); 
関連する問題