Закрытие JavaScript теряет эту ссылку? - PullRequest
2 голосов
/ 09 декабря 2011

Рассмотрим следующий код:

<script>
    var i = 0;
    function test() {
        var _this = this;
        // foo and _this.foo are set to the same number
        var foo = _this.foo = i++;

        function wtf() {
            console.log(_this.foo, foo);
        }

        $("#thediv").click(wtf);
    };
    test();
    test();
    test();
</script>

Кажется, что console.log (_this.foo, foo) всегда должен выводить одинаковые числа (i).

Но при нажатии на выходы div3 строки (для каждого вызова console.log):

2 0
2 1
2 2

Кажется, что _this.foo всегда относится к последнему this.foo.Почему это так?

Ответы [ 5 ]

3 голосов
/ 09 декабря 2011

В вашей функции wtf значение, захваченное в переменной foo, представляет собой скаляр - фактическое числовое значение.Так как он захватывает скалярное значение в момент создания функции, эта функция закрывается по значению 0, 1, 2 и т. Д. Вот почему она, похоже, увеличивается.

Однако, когда _this захвачен, он захватывается как ссылка на один экземпляр, который имеет поле с именем foo.Следовательно, с _this.foo вы ссылаетесь на поле в том же экземпляре.

Таким образом, чтобы подвести итог, типы значений, такие как целые числа, фиксируются по их значению, тогда как объект захватывается по его ссылке.

2 голосов
/ 09 декабря 2011

Когда выполняется test (), this является ссылкой на window для каждого из трех вызовов test (), поэтому вы фактически обновляете window.foo, когда назначаете _this.foo и ссылаетесь на window.foo в вашем console.log.

Затем, когда вызывается wtf(), переменные _this в каждом из wtf() замыканий одинаковы - все они указывают на window

Смотрите это jsfiddle: http://jsfiddle.net/8cyHm/

Я добавил некоторые дополнительные параметры в console.log, чтобы показать, что происходит

1 голос
/ 10 декабря 2011

Итак, вот как это работает:

Функция test вызывается три раза.Каждый раз, когда создается другой функциональный объект wtf, который привязывается к DIV в качестве обработчика щелчков.Это означает, что после выполнения приведенного выше кода к DIV будут привязаны обработчики трех щелчков .Когда вы затем нажимаете на DIV, эти три обработчика вызываются последовательно.

Эта строка

var _this = this;

просто сохраняет глобальный объект в локальной переменной _this.Если функция test должна вызываться в среде строгого режима, this будет undefined, и код выдаст ошибку.Однако, поскольку это не строгий режим, значение this относится к глобальному объекту.

Кстати, переменная i объявлена ​​в глобальном коде, что делает ее глобальной переменной (глобальное свойство).

Эта строка

var foo = _this.foo = i++;

назначает текущее значение i как локальной переменной foo, так и _this.foo.А поскольку _this является ссылкой на глобальный объект, свойство foo является глобальным свойством (как и i).

Теперь, так как мы вызывали функцию test три раза, есть также три отдельные foo локальные переменные.Каждая из этих переменных фиксирует значение переменной i в момент вызова функции test.Итак, значения этих трех foo переменных: 0, 1 и 2.Эти переменные фиксируются тремя функциями wtf (соответственно) через замыкание.(Первая функция wtf захватывает первую переменную foo и т. Д.)

Однако, в отличие от переменных foo, в имеется только одно глобальное свойство foo,Таким образом, после каждого вызова функции test глобальное свойство foo увеличивается.В результате после трехкратного вызова test значение _this.foo равно 2.(Это до нажатия кнопки DIV.)

Теперь, когда нажата кнопка DIV, будут выполнены три функции wtf.Каждая из этих функций напечатает значение _this.foo, равное 2.Однако каждая из этих wtf функций захватила различную переменную foo через замыканиеЗначения этих трех foo переменных равны 0, 1 и 2 соответственно.

1 голос
/ 09 декабря 2011

Это хитрый,:)

Первое, что вы должны понять, это то, что вы вызываете функцию test без префикса new, что заставляет указатель this внутри функции ссылаться на объект window

<script>
    var i = 0;
    function test() {
        var _this = this; //** this referes to the window object
        var foo = _this.foo = i++; //** incrementing the global var and assigning that to a local var and a window.foo var

        function wtf() {
            console.log(_this.foo, foo); //** reads window.foo and its local var foo
        }

        $("#thediv").click(wtf); //** creates a new lister every time the test function gets called
    };
    //** calling without the new keyword
    test(); //** creates foo-1, and wft-1 in memory, assigns foo-1=0; window.foo=0
    test(); //** creates foo-2, and wft-2 in memory, assigns foo-2=1; window.foo=1
    test(); //** creates foo-3, and wft-3 in memory, assigns foo-3=2; window.foo=2
</script>

(пожалуйста, прочитайте закомментированную часть внутри кода)

Теперь, когда вы нажимаете на div, который практически имеет 3 функции, слушающие его событие нажатия (3 встроенные функции wtf внутри функции test) (каждый вызов функции test создает новую wtf встроенная функция). Каждая из этих встроенных функций считывает свою локальную переменную foo, каждая из которых имеет значения 1,2,3 соответственно.

0 голосов
/ 09 декабря 2011

Если вы тестируете в Chrome, вы можете столкнуться с ошибкой в ​​console.log.См .: Ошибка массива Javascript Funky

Попробуйте изменить на:

console.log(_this.foo + ' = ' + foo);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...