Шаблон раскрывающего модуля Javascript, публичные свойства - PullRequest
24 голосов
/ 17 января 2012

Я пытаюсь разобраться с шаблоном разоблачающего модуля в 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 не обновляется.Если я проверю значение totalPoints в пределах , функция addPoints будет правильно увеличена на *1009*. Что происходит?

  2. Если я использую консоль для проверки window.addPoints или window.getPoints, я могу видеть это, потому что я не использовал "var" вперед объявлениями функций они были добавлены в глобальную область видимости. Разве это не неправильно? Большинство примеров, на которые я смотрю, похоже, делают это.

Любые указатели с благодарностью получены.

Ответы [ 2 ]

32 голосов
/ 17 января 2012

Вы передаете номер здесь:

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

Использование геттеров и сеттеров

Другое решение заключается в использовании геттеров , которые позволят дать вам возможность получить обновленное значение всего с george.totalPoints, хотя геттеры пока широко не поддерживаются (пока). Вы можете реализовать геттер так:

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 = ...;
0 голосов
/ 20 марта 2015

Это немного другое решение, которое не требует геттера / установщика и сохраняет totalPoints как свойство.

    var Child = function () {

        var _api;

        return _api = {

            addPoints: addPoints,
            points: 100
        };

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

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

    };
...