在构造函数中向原型添加属性

发布于 2024-11-29 00:53:34 字数 863 浏览 0 评论 0原文

我正在尝试一些示例,并遇到一个问题,如果我们想向原型添加一个函数,它将无法访问构造函数的私有成员。我遇到了这个解决方案。这似乎是一个不错的技巧。

我尝试了其他一些方法,得到了以下结果:

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。难道是有什么问题吗?

I was experimenting with some examples and came across a problem that if we want to add a function to a prototype it will not be able to access the private members of the constructor. I came across this solution. This seems to be a nice hack.

I tried out some other ways and I got the following:

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

The solution seems weird because we are adding to the prototype within the constructor function. (I haven't seen much of this). It works on firefox 5 and chrome at least. Is there something wrong with it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

热鲨 2024-12-06 00:53:34

您所做的就是每次创建新的餐厅对象时在原型上重新定义这些方法。更明智的方法是在 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< /code>:

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
  };
}

然后,如果您想更改函数是否是私有的,只需在返回的函数中添加或删除它即可目的。

What you're doing is redefining those methods on the prototype every time you make a new restaurant object. The more sane way to do that would be to define them on this, which is the new object being constructed in a constructor:

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();
    }
}

You could just do it like this though, and not use 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();
    }
  };
}

and then just do:

var restaurant = RestaurantMaker();

This is called the revealing module pattern. The downside is that each new object gets a copy of all the functions, which also happens if you add methods to this in your constructor.

A very small alternative version of the revealing module pattern (which I think reads a bit better) looks like 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
  };
}

Then, if you want to change whether a function is private or not, it's just a matter of adding or removing it from the returned object.

雾里花 2024-12-06 00:53:34

我实际上没有对此进行测试,但我认为所有对象都会访问最后实例化对象的私有属性。

在每个实例化中,您将原型方法(在所有实例之间共享)绑定到正在实例化的对象的私有变量:)

I didn't actually test this, but I think all the objects would access to the last instantiated object's private properties.

On each instantiation you're binding the prototype methods (shared across all instances) to the private variables of the object being instantiated :)

┾廆蒐ゝ 2024-12-06 00:53:34

老实说,这对我来说没有多大意义。当然,您可以通过这种方式调用您的私有函数,但这并不能解决最初的问题 - 也就是说,您仍然需要在构造函数中添加方法。

如果你想在构造函数之外向类添加方法,你可以使用闭包来保持构造函数的干净:

// 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

Honestly, it doesn't make a lot of sense to me. Sure, you can have calls to your private functions this way, but it doesn't solve the initial problem - that is, you still need to add methods inside the constructor.

If you want to add methods to the class outside the constructor, you can use closures to keep constructors clean:

// 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
作妖 2024-12-06 00:53:34

我们采取不同的方法。我们有时确实会使用闭包,但仅当您需要在类级别管理状态时才使用。我们使用命名空间来管理范围。对于具有原型方法的简单类,我们只需这样做:

/**
 * @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;
    }
})();

We take a different approach. We do use closures sometimes, but only when you need to manage state at the class level. We use namespaces to manage scope. For a simple class with prototype methods, we just do this:

/**
 * @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;
    }
})();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文