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的方式修改了它,在它们的
“类”
中感谢您的解释和注释。每次创建对象时,我都会重新定义原型中的方法,这一点我完全忽略了。我之前看过模块化模式。但我所面临的问题是,每次我打电话给
餐厅制造商
时,我都会收到
使用卫生间
购买食物
的新实例。这是不需要的,也就是说,如果可以将它们添加到原型中,它们就可以被共享。问题是,只有当函数定义在与私有变量相同的范围内时,它才能访问私有变量。所以如果你是