Javascript变量复制范围
我有两段代码,我相信它们会产生相同的结果: 一,Javascript变量复制范围,javascript,function,scope,closures,Javascript,Function,Scope,Closures,我有两段代码,我相信它们会产生相同的结果: 一, 用于(var i=0;i这是setTimeout,它延迟执行直到浏览器可用,或者在本例中是0.1秒之后,当循环阻塞浏览器时,直到循环完成后才会执行超时,此时变量i等于它在循环中设置的最后一个值,因为循环在此之前已经完成或者执行setTimeout中的代码 通过将变量作为循环内的参数传递给另一个函数,该变量是该函数作用域的局部变量,并使其值与迭代无关 for(var i=0;i<10;i+=1){ var j=i;
用于(var i=0;i这是setTimeout,它延迟执行直到浏览器可用,或者在本例中是0.1秒之后,当循环阻塞浏览器时,直到循环完成后才会执行超时,此时变量i
等于它在循环中设置的最后一个值,因为循环在此之前已经完成或者执行setTimeout中的代码
通过将变量作为循环内的参数传递给另一个函数,该变量是该函数作用域的局部变量,并使其值与迭代无关
for(var i=0;i<10;i+=1){
var j=i; // j is constantly updated and it's also hoisted
setTimeout(function(){ // and this runs last, when the browser is no longer
console.log(j); // locked, so j is the last value it was set to
},100);
}
在第一个代码示例中,for(var i=0;i在循环的迭代中,j
没有绑定i
的值。这是因为不能在循环中声明变量。循环在JavaScript中没有作用域,只有函数有作用域
第一个代码示例相当于:
var i, j; // all variable declarations are hoisted to the top
for (i = 0; i < 10; i += 1) {
j = i;
setTimeout(function() {
console.log(j);
}, 100);
}
var i,j;//所有变量声明都被提升到顶部
对于(i=0;i<10;i+=1){
j=i;
setTimeout(函数(){
控制台日志(j);
}, 100);
}
由于在第二个代码示例中,j
是在匿名立即数函数中声明的,因此它在该迭代中绑定到i
的值,这是一个传递值技巧。这称为关闭范围或简单的闭包
var j在每次迭代中创建一个新变量j
for(var i=0;i<10;i+=1){
var j=i; // j is constantly updated and it's also hoisted
setTimeout(function(){ // and this runs last, when the browser is no longer
console.log(j); // locked, so j is the last value it was set to
},100);
}
不幸的是,您所想的并不是Javascript所想的。在Javascript中,所有变量声明都会移动到封闭函数的顶部,因此当您键入
function(){
for(var i=1; i<10; i++){
然而,在Javascript中,内部变量声明被挂起,因此实际上就像您编写了
var x;
x = 1;
if(true){
x = 2;
}
console.log(x);
第二种方法是使用闭包来保持i的值
事实上,您看到的两个结果都是闭包工作方式的结果。您传递给setTimeout
的两个函数都是闭包
我认为第一个也应该保留价值,因为:
var j在每次迭代中创建一个新变量j
for(var i=0;i<10;i+=1){
var j=i; // j is constantly updated and it's also hoisted
setTimeout(function(){ // and this runs last, when the browser is no longer
console.log(j); // locked, so j is the last value it was set to
},100);
}
不,它没有。在第一个示例中只有一个j
。在JavaScript中(目前),变量仅具有函数或全局作用域,从不阻塞作用域。JavaScript对第一个示例的实际作用看起来更像这样:
var i;
var j;
for(i=0;i<10;i+=1){
j=i;
setTimeout(function(){
console.log(j);
},100);
}
相反:
for(var i=0;i<10;i+=1){
setTimeout(makeHandler(i));
}
function makeHandler(j){
return function(){
console.log(j);
};
}
for(var i=0;i这是可行的,使用let
而不是var
(let
在2013年被问到这个问题时并不存在):
用于(设i=0;isovar j
不会在每次迭代中创建新的j?不,for循环中没有特殊的作用域,因此j是循环所处的任何作用域的局部,变量被提升,所以你需要一个闭包来保持引用期间的值不变,这是一个很好的术语。你想到了吗?@FritsvanCampen:是的,我花了一段时间但是当我最终这样做的时候,我很高兴。”在每次迭代中,var j
创建一个新的变量j“不,它没有。
var x;
x = 1;
if(true){
x = 2;
}
console.log(x);
var i;
var j;
for(i=0;i<10;i+=1){
j=i;
setTimeout(function(){
console.log(j);
},100);
}
for(var i=0;i<10;i+=1){
var f1 = function(j){
var f2 = function(){
console.log(j);
};
setTimeout(f2,100);
};
f1(i);
}
for(var i=0;i<10;i+=1){
setTimeout(makeHandler(i));
}
function makeHandler(j){
return function(){
console.log(j);
};
}
for(let i=0;i<10;i+=1){
let j=i;
setTimeout(function(){
console.log(j);
},100);
}