javascript变量作用域问题谢谢
怪我咯
怪我咯 2017-04-10 14:51:04
[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??
怪我咯
怪我咯

走同样的路,发现不同的人生

全部回复(4)
巴扎黑

很多答案說是 因爲 閉包,這是錯誤的。

即便沒有閉包,由於 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.

黄舟

注意 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++) {
var c = i;
a[i] = (function (u) {
return function(){
console.log(u);
}
}(c));
}

巴扎黑

闭包的关系,赋值的时候自成作用域.

这样更好理解一点:
var a = [];
for (var i = 0; i < 10; i++) {
(function() {
var c = i;
a[i] = function() {
console.log(c);
};
})();
}

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号