Javascript 在构造函数中向原型添加属性
我在尝试一些示例时遇到了一个问题,即如果我们想向原型添加函数,它将无法访问构造函数的私有成员。我找到了解决办法。这似乎是一个不错的黑客 我尝试了其他一些方法,得到了以下结果:Javascript 在构造函数中向原型添加属性,javascript,constructor,prototype-programming,Javascript,Constructor,Prototype Programming,我在尝试一些示例时遇到了一个问题,即如果我们想向原型添加函数,它将无法访问构造函数的私有成员。我找到了解决办法。这似乎是一个不错的黑客 我尝试了其他一些方法,得到了以下结果: var Restaurant = function() { var myPrivateVar; var private_stuff = function() // Only visible inside Restaurant() { return "I can set 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
这个解决方案看起来很奇怪,因为我们正在构造函数中添加原型。(我没怎么看过)。它至少可以在Firefox5和chrome上运行。它有什么问题吗?我实际上没有测试它,但我认为所有对象都可以访问上一个实例化对象的私有属性
在每次实例化时,您都将原型方法(在所有实例中共享)绑定到被实例化对象的私有变量:)老实说,这对我来说没有多大意义。当然,您可以通过这种方式调用私有函数,但这并不能解决最初的问题——也就是说,您仍然需要在构造函数中添加方法 如果要向构造函数外部的类添加方法,可以使用闭包保持构造函数干净:
// 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
每次创建新的餐厅对象时,您都要在原型上重新定义这些方法。更明智的方法是在
上定义它们,这是在构造函数中构造的新对象:
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();
这称为显示模块模式。缺点是,每个新对象都会获得所有函数的副本,如果在构造函数中向中添加方法,也会发生这种情况
显示模块模式的一个非常小的替代版本(我认为读起来更好)如下所示:
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
};
}
然后,如果要更改函数是否为私有函数,只需在返回的对象中添加或删除它即可。我们采用不同的方法。我们有时会使用闭包,但只有在需要在类级别管理状态时才使用闭包。我们使用名称空间来管理范围。对于具有原型方法的简单类,我们只需执行以下操作:
/**
* @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;
}
// namespace 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 closure can call this
function sellItem (item, quantity) {
if (!itemsSold.hasOwnProperty(item)) {
itemsSold[item] = 0;
}
itemsSold[item] += quantity;
}
})();
/**
*@名称空间
*/
var-chain={};
(功能(){
/**
*构造函数用于管理私有数据
*@constructor
*/
连锁餐厅=功能(){
//仅在此构造函数内可见
var存货={};
/**
*将具有计数的项目添加到库存
*这是一项特权功能。
*@param{String}item您正在添加的项的标识符
*@param{String}count为项目添加的计数。
*/
this.addInventory=函数(项,计数){
如果(计数<0){
//出错
}
var current=此.getInventory(项目);
存货[项目]=当前+盘点;
}
//特权函数
this.getInventory=函数(项目){
if(存货.自有财产(项目)){
退货存货[项目];
}
返回0;
}
//特权函数
this.removInventory=函数(项,计数){
throwIfNegative(计数);
if(此.getInventory(项目)<计数){
抛出新错误(“库存不可用”);
}
存货[项目]-=盘点;
}
//私有函数,仅对特权函数可见
函数throwIfNegative(值){
如果(值<0){
抛出新错误(“负库存无效”);
}
}
}
//成员/原型法
chain.Restaurant.prototype.sellInventory=函数(项目、计数){
var Available=此.getInventory(项目);
var sellCount=Math.min(可用,计数,0);
如果(sellCount>0){
//如果调用函数有影响,则有条件地执行此操作
此。删除库存(sellCount);
sellItem(item,sellCount);
}
返回销售计数;
}
//成员/原型法
chain.Restaurant.prototype.hasInventory=函数(项目、计数){
返回此项。getInventory(item)>=计数;
}
//名称空间方法
chain.soldQuantity=功能(项目){
如果(!itemsSold.hasOwnProperty(项目)){
返回0;
}
退货项目库存[项目];
}
//在此闭包中定义的函数可以看到
var itemsSold={};
//此闭包中定义的所有函数都可以调用
功能项目(项目、数量){
如果(!itemsSold.hasOwnProperty(项目)){
itemsSold[项目]=0;
}
itemsSold[项目]+=数量;
}
})();
不必在全局范围内定义餐厅
,然后分配给它,您只需在闭包内说窗口。餐厅
。是的,您是对的,它甚至可以从自调用函数返回,所以它可以分配给任何变量。这里的问题是,餐厅
的所有实例都将共享相同的privateVar
,这可能是OP想要的,也可能不是OP想要的。我用LiveScript的方式修改了它,在它们的“类”
中感谢您的解释和注释。每次创建对象时,我都会重新定义原型中的方法,这一点我完全忽略了。我之前看过模块化模式。但我所面临的问题是,每次我打电话给餐厅制造商
时,我都会收到使用卫生间
和购买食物
的新实例。这是不需要的,也就是说,如果可以将它们添加到原型中,它们就可以被共享。问题是,只有当函数定义在与私有变量相同的范围内时,它才能访问私有变量。所以如果你是