Это описывает распространенную ошибку с использованием замыканий в JavaScript.
. Рассмотрим:
function makeCounter()
{
var obj = {counter: 0};
return {
inc: function(){obj.counter ++;},
get: function(){return obj.counter;}
};
}
counter1 = makeCounter();
counter2 = makeCounter();
counter1.inc();
alert(counter1.get()); // returns 1
alert(counter2.get()); // returns 0
Для каждого времени makeCounter
, {counter: 0}
приводит к созданию нового объекта. Кроме того, создается новая копия obj
для ссылки на новый объект. Таким образом, counter1
и counter2
не зависят друг от друга.
Использование замыкания в цикле является сложным.
Рассмотрим:
var counters = [];
function makeCounters(num)
{
for (var i = 0; i < num; i++)
{
var obj = {counter: 0};
counters[i] = {
inc: function(){obj.counter++;},
get: function(){return obj.counter;}
};
}
}
makeCounters(2);
counters[0].inc();
alert(counters[0].get()); // returns 1
alert(counters[1].get()); // returns 1
Обратите внимание, что counters[0]
и counters[1]
независимы не . Фактически, они работают на одном и том же obj
!
Это связано с тем, что есть только одна копия obj
, разделенная на все итерации цикла, возможно, по соображениям производительности. Несмотря на то, что {counter: 0}
создает новый объект на каждой итерации, одна и та же копия obj
будет просто обновляться с ссылкой на самый новый объект.
Решение состоит в использовании другой вспомогательной функции:
function makeHelper(obj)
{
return {
inc: function(){obj.counter++;},
get: function(){return obj.counter;}
};
}
function makeCounters(num)
{
for (var i = 0; i < num; i++)
{
var obj = {counter: 0};
counters[i] = makeHelper(obj);
}
}
Это работает, потому что локальные переменные в области функции напрямую, а также переменные аргументов функции выделяются новыми экземплярами при записи.
Подробное обсуждение см. в JavaScript ловушки закрытия и использование
Как предложил Питер Кордес, я представляю данные как шестнадцатеричные значения:
RR RR RR RR EE EE HH LL
| | || ||
| | || AL
| | AH |
| | |___|
| | AX |
| |_________|
| EAX |
|_____________________|
RAX
... где RAX
- 64-битный регистр, который существует в x86-64
.
Итак, если у вас были AH = 0x12
и AL = 0x34
, вот так:
00 00 00 00 00 00 12 34
| | || ||
| | || AL
| | AH |
| | |___|
| | AX |
| |_________|
| EAX |
|_____________________|
RAX
... тогда у вас были AX = 0x1234
и EAX = 0x00001234
и т. д.
Обратите внимание, что, как показано на этой диаграмме, AH
является единственным «странным» регистром, который не согласован с нижними битами. Остальные (AL
, AX
, EAX
, RAX
для 64-битных) имеют разные размеры, но все выровнены справа. (Например, два байта, отмеченные EE EE
на диаграмме, сами не имеют имени регистра.)