为什么不在功能副本中分配变量而不是引用它
我有此代码:
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function () {
console.log(i);
// that should show its number
};
shooters.push(shooter); // and add it to the array
i++;
}
// ...and return the array of shooters
return shooters;
}
let army = makeArmy();
// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.
发生这种情况是因为i
始终是对makearmy()
函数内部i
的引用。
如果我们将代码调整为:
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
// copy the varible i into the while lexical scope
let j = i
let shooter = function () {
console.log(j);
// that should show its number
};
shooters.push(shooter); // and add it to the array
i++;
}
// ...and return the array of shooters
return shooters;
}
let army = makeArmy();
army[0](); // 0
army[1](); // 1
army[2](); // 2
上述代码按预期工作,因为而不是引用变量i
shooter()我们将其复制到j ,因此可以在其自身范围内对射击器功能可用。
现在,我的问题是,为什么在函数本身内部复制i
变量?即使我仍在有效地复制该变量?我在这里想念什么?
代码:
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function () {
let j = i;
console.log(j);
// that should show its number
};
shooters.push(shooter); // and add it to the array
i++;
}
// ...and return the array of shooters
return shooters;
}
let army = makeArmy();
// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.
I have this code:
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function () {
console.log(i);
// that should show its number
};
shooters.push(shooter); // and add it to the array
i++;
}
// ...and return the array of shooters
return shooters;
}
let army = makeArmy();
// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.
This happens because i
is always a reference to the outer i
inside the makeArmy()
function.
If we adjust the code to be:
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
// copy the varible i into the while lexical scope
let j = i
let shooter = function () {
console.log(j);
// that should show its number
};
shooters.push(shooter); // and add it to the array
i++;
}
// ...and return the array of shooters
return shooters;
}
let army = makeArmy();
army[0](); // 0
army[1](); // 1
army[2](); // 2
The above code works as expected because instead of referencing the variable i
inside shooter()
we are copying it into j
, thus making it available to the shooter function in its own scope.
Now, my question is, why doesn't copying the i
variable inside the function itself work? even though I'm effectively still copying the variable? What am I missing here?
Code:
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function () {
let j = i;
console.log(j);
// that should show its number
};
shooters.push(shooter); // and add it to the array
i++;
}
// ...and return the array of shooters
return shooters;
}
let army = makeArmy();
// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因为您正在复制
i
已经是10
的时候。实际上,使用
让j = i
在 Inner 函数中,直接使用i
没有区别,因为该分配也仅执行当您调用该内部函数时,如前所述, i 已经是10
,因为调用在循环完成后很长时间发生,在EG陆军中[0]()
。如您指出的那样,如果您将
移动j = i
在内部功能之外(但仍在循环内),则可以工作。这样,对本地变量j
的评估立即发生在每个迭代上,并且内部功能随后涉及其正确值的10种不同的j
以前是在i
具有您想要的相应值的那个时间点设置的。顺便说一句,如果您将循环使用
使用
让让具有一些“魔术”,则此问题将不存在为每次迭代创建一个半分开的范围(此工作的确切方式是更复杂的)。Because you are copying at a time at which
i
is already10
.In fact, with
let j = i
in the inner function, there will be no difference to usingi
directly, because that assignment also executes only when you invoke that inner function, and as said, at this pointi
will already be10
, since the invocation happens long after the loop completed, in e.g.army[0]()
.As you noted, it works if you move the
let j = i
outside of the inner function (but still inside the loop). This way, the assigment to the local variable(s)j
happens on each iteration immediately, and the inner function later refers to those 10 differentj
's with their right values that were previously set at that point in time wheni
had the respective value that you wanted.By the way, this problem won't exist if you'd use a
for
loop instead becausefor
withlet
has some "magic" that creates a semi-separated scope for each iteration (the exact way this works is a bit more complicated).当您调用
console.log(i)
在您的射击器函数i
的值中是指一个while循环结束的值,因此我将是最后一个值它有。在您的情况下,i
的值会随着时间而变化,显示了它的最后一个值。当您将其分配给变量(令j = i
)时,您会复制该值而不是参考,以便您为您提供所需的结果。When you call
console.log(i)
in your shooter functioni
's value refers to the one that has once the while loop ended, thus i would be the last value it had. In your casei
's value changes over time, showing the last value it had. When you assign that to a variable (let j = i
) you copy that value and not the reference so it gives you the result you want.