Создание нескольких экземпляров модуля
Я думал, что начинаю понимать JavaScript довольно хорошо, но явно нет. Позвольте мне объяснить мою проблему на примере. Сначала у меня есть следующий модуль:
var Test = function() {
var counter = 0;
function init() {
alert(counter);
}
return {
counter: counter,
init: init
}
};
Затем создаю 2 экземпляра:
var test1 = new Test();
var test2 = new Test();
Теперь я обновляю переменную счетчика (поскольку она является общедоступной) и делает некоторые предупреждения. Пока все хорошо.
alert(test1.counter); // Alerts 0
test1.counter = 5;
alert(test2.counter); // Alerts 0
test2.counter = 10;
alert(test1.counter); // Alerts 5
Теперь, наконец, я говорю следующее:
test1.init(); // Alerts 0
test2.init(); // Alerts 0
Это бит, который я не понимаю. Почему это предупреждение 0? Я думал, что первое предупреждение будет 5, а второе 10.
Я был бы признателен, если бы кто-нибудь мог объяснить, как это работает, или указать мне в правильном направлении. Благодаря
Ответы
Ответ 1
Он остается 0
, потому что вы не меняете переменную внутри Test
, вы меняете объект, возвращаемый функцией. counter
поддерживается "private", и только функция из Test
может получить к нему доступ.
var Test = function() {
var counter= 0;
function init() {
alert(counter);
}
function changeNum(n){
counter = n; //add a function inside `Test` so that it can
} //access the variable
return {
counter: counter,
init: init,
changeNum: changeNum
}
};
Теперь он будет работать: http://jsfiddle.net/DerekL/pP284/
var test1 = new Test();
alert(test1.counter); //0
test1.init(); //0
test1.changeNum(5);
alert(test1.counter); //5
test1.init(); //5
Для получения дополнительной информации см. Закрытие JavaScript.
Ответ 2
Вот что произошло:
- функция init() сделала замыкание на переменной
counter
, которая определена внутри области проверки, содержащая ссылку на нее.
- Возврат из функции Test() создал новый объект с другой переменной
counter
, установленный для значения внутреннего counter
.
- Вы обновляете это "другое"
counter
, устанавливая test1.counter = X, но init() по-прежнему содержит ссылку на исходную переменную.
Вот почему вы видите старое значение.
Ответ 3
Я не уверен, что вы допустили ошибку в своем сообщении, но вы можете переписать вышеуказанный код следующим образом
var Test = function() {
this.counter = 0;
}
Test.prototype.init = function() {
alert(this.counter);
}
var test1 = new Test();
var test2 = new Test();
test1.counter = 5;
test2.counter = 10;
test1.init(); // alerts 5
test2.init(); // alerts 10
В вашем примере вы не устанавливаете счетчик как свойство в свой тестовый объект/функцию, а при вызове test1.counter
вы по существу устанавливаете новое свойство, которого раньше не было, а ваша функция init не ссылаясь на это свойство.
Как показывают ответные ответы dereks, вы, кажется, немного смутили два разных шаблона между тем, на что мой ответ следует, и его.
Ответ 4
Вот что я сделал бы:
function Test() {
this.counter = 0;
this.init = function() { console.log(this.counter); }
};
var test1 = new Test();
var test2 = new Test();
console.log(test1.counter); //0
test1.counter = 5;
console.log(test2.counter); //0
test2.counter = 10;
console.log(test1.counter); //5
test1.init(); //5
test2.init(); //10