JavaScript揭示模块模式,公共属性

25

我正在努力理解JavaScript中的透明模块模式。以下代码片段中的两件事让我感到困惑。

        var Child = function () {
            var totalPoints = 100;
            addPoints = function (points) {
                totalPoints += points;
                return totalPoints;
            };
            getPoints = function () {
                return totalPoints;
            };
            return {
                points: totalPoints,
                addPoints: addPoints
            };
        };
        $(function () {
            var george = Child();
            console.log(george.points);
            console.log(george.addPoints(50));
            console.log(george.points);
        });
  1. 这里在控制台上打印的三个值分别是100、150和100。这告诉我,当我使用一个值调用“addPoints”函数时,变量totalPoints没有被更新。如果我在addPoints函数中检查totalPoints的值,它已经正确地被增加了。发生了什么事情?

  2. 如果我使用控制台检查window.addPoints或window.getPoints,我会发现因为我没有在函数声明前面使用“var”,它们已经被添加到全局作用域中。这难道不是错误的吗?我看到的大多数例子都这样做。

非常感谢任何指导。

2个回答

33

这里您传递了一个数字:

return {
    points: totalPoints,
    addPoints: addPoints
};
这段代码与以下代码没有任何区别:
return {
    points: 100,
    addPoints: addPoints
};
你正在传递一个值,而不是对 totalPoints 的引用(在 JavaScript 中后者不可能)。因此,当 totalPoints 改变时,对象中的值不会改变。

使用函数

为了解决这个问题,最简单的方法是使用一个函数来获取最新的结果(比如已经有的 getPoints 函数)。 这个 JSFiddle 给出了一个完整的例子:点击这里
return {
    points: function(x) { return totalPoints; }, // always up-to-date
    addPoints: addPoints
};
缺点是现在调用者必须通过函数调用来获取points
console.log(george.points());

使用getter和setter

另一种解决方案是使用getter,只需使用george.totalPoints即可获取更新后的值,但是目前并不广泛支持 getter。您可以像这样实现一个 getter:

var obj = {};

obj.points = addPoints;

// add a "special" property to the object instead of normal notation
Object.defineProperty(obj, "totalPoints", {
    get: function() { // function that's executed when you use `.totalPoints`
        return totalPoints;
    }
});

return obj;
其次,删除var会使函数变成全局的,这是正确的但不建议这样做。如果你是想要一行声明多个变量,可以使用逗号隔开的单个var语句:
var totalPoints = 100, // expands to three `var` statements, so no
    addPoints = ...,   // global variables
    getPoints = ...;

1
谢谢。这非常有帮助,所以我写了一篇关于它的文章,需要使用设置器和获取器 http://geekswithblogs.net/Aligned/archive/2013/01/15/setting-a-var-property-in-the-javascript-revealing-module-pattern.aspx。希望能帮到某些人。 - AlignedDev
找到与此相关的错误让我疯狂了45分钟! - weiglt

0

这是一个稍微不同的解决方案,它不需要getter/setter并保留totalPoints作为属性。

    var Child = function () {

        var _api;

        return _api = {

            addPoints: addPoints,
            points: 100
        };

        /* ----------- */

        function addPoints(points) {
            _api.points += points;
            return _api.points;
        };

    };

这提供了一个“类似getter”的字段,但没有setter - 它仍然是一个函数。 - Chris Walsh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接