下面的代码如果使用var,最后输出的是9。
var a = [];
for (var i = 0; i < 10; i++) {
var c = i;
a[i] = function () {
console.log(c);
};
}
a[6](); // 9为什么一直输出是9??
求高手详解,谢谢
var a = [];
for (var i = 0; i < 10; i++) {
let c = i;
a[i] = function () {
console.log(c);
};
}
a[6](); // 6 //为什么这次是6??
注意 let 为 ECMAScript 6新增的命令,在部分低版本浏览器不支持;
let 起到的作用就是申明了块范围变量;
这样console.log(c);就输出了 块范围变量 c
使用var方式定义的c 在for循环结束之后,已经变成了9;
而 a[0]-a[9] 方法中的 console.log(c); 这里的c 又指向了全局变量,所以就一直输出9了;
那么问题来了,这不是我想要的,我那个for循环有屁用啊!!
所以我们要让 console.log(c); 指向局部变量,这就要用到闭包了,
a[i] = (function (u) {
return function(){
console.log(u);//这里的u就指向了 参数 u
}
}(c));//这里通过参数的方式将 c 传进去
推荐看下变量对象的概念:变量对象(Variable Object)
闭包的关系,赋值的时候自成作用域.
这样更好理解一点:
var a = [];
for (var i = 0; i < 10; i++) {
(function() {
var c = i;
a[i] = function() {
console.log(c);
};
})();
}
很多答案說是 因爲 閉包,這是錯誤的。
即便沒有閉包,由於 var
的自動提前,得到的結果仍舊是 9。所以閉包並不是出現這種情況的原因。
正確的原因在於 javascript 的 var
的作用域是函數,而非 block。let
就是讓作用域成爲 block 的。
樓下說只有 IE11 支持,這也是錯的。
引用 mdn:
Note: The let keyword is only available to code blocks in HTML wrapped in a <script type="application/javascript;version=1.7"> block
(or higher version). XUL script tags have access to these features
without needing this special block.
可見目前使用 let 還需要額外的配置,但不代表瀏覽器不支持。
參見:http://stackoverflow.com/questions/762011/javascript-let-keyword-vs-var-keyword
var
is scoped to the nearest function block (or global if outside a
function block), andlet
is scoped to the nearest enclosing block
(or global if outside any block), which can be smaller than a function
block.Also, just like
var
, variables declared withlet
are visible
before they are declared in their enclosing block, as shown in the
demo.
var
的作用域是函數,而 let
的作用域是 statement group。
因此,使用 var
的版本,閉包中原先的數值被循環改變;
而使用 let
的版本,閉包中的數值的作用域小於循環的作用域,沒有被改變,從而保留了原始值。
無論 var
還是 let
,都會自動被提前。
var a = b
實際上等價於 var a; a = b
; 提前的只是 var a
。所以你在 for
裏面 var a
跟在外面是一樣的。
也可以認爲使用 let
等價於這樣:
var a = [];
for (var i = 0; i < 10; i++)
(function(c) {
a[i] = function() {
console.log(c);
};
}(i));
a[6]();
注:標準當中,let
是不會提前的,但似乎並沒有被很好地支持。
In ECMAScript 6, let does not hoist the variable to the top of the
block. If you reference a variable in a block before the let
declaration for that variable is encountered, this results in a
ReferenceError, because the variable is in a "temporal dead zone" from
the start of the block until the declaration is processed.
因为闭包
var a = [];
for (var i = 0; i < 10; i++) {
var c = i;
a[i] = (function (u) {
return function(){
console.log(u);
}
}(c));
}