2013-02-09 8 views
15

Я думал, что начинаю понимать 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.

Я был бы признателен, если бы кто-нибудь мог объяснить, как это работает, или указать мне в правильном направлении. Благодаря

+4

Скалярное набраны переменные передаются по значению, а не по ссылке. Итак, 'return {counter: counter, ...}' просто копирует текущее значение 'var counter' и меняет' this.counter', не влияет на 'var counter'. –

ответ

11

Он остается 0, потому что вы не меняете переменную внутри Test, вы меняете объект, возвращаемый функцией. counter хранится «частным», и только функция в 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 Closures.

+0

Большое спасибо. Это хорошо очистило. – nfplee

+0

И почему может быть Test на глобальном пространстве, доступном для всех скриптов? – AntonioRomero

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, вы, похоже, немного смутили два разных шаблона между тем, который я получил в ответ, и его.

5

Это то, что случилось:

  1. функция инициализации() сделал замыкание на counter переменной, которая определена внутри рамки испытаний, держа ссылку на него.
  2. Возврат из функции Test() создал новый объект с другой переменной counter, установленный в значение внутреннего counter.
  3. Вы обновили это «другое» counter, установив test1.counter = X, но init() все еще содержит ссылку на исходную переменную.

Вот почему вы видите старую ценность.

+0

Спасибо за дополнительное разъяснение. Я отдал Дереку ответ просто потому, что он пришел перед твоим, и это в равной степени помогло мне. – nfplee

0

Вот что я хотел бы сделать:

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 
Смежные вопросы