首页 > javascript变量作用域问题谢谢

javascript变量作用域问题谢谢

下面的代码如果使用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), and let 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 with let 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));
}

【热门文章】
【热门文章】