var 和 let 的区别?

2016-11-15 23:19:31 +08:00
 brooky
var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10   
var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

想不明白了, 谁能帮忙解释下这是为啥呢?

5757 次点击
所在节点    JavaScript
31 条回复
ryanzyy
2016-11-16 08:48:36 +08:00
for (var i = 0; i < 10; i++) console.log(i);
i -> 10
for (let i = 0; i < 10; i++) console.log(i);
i -> undefined
ChefIsAwesome
2016-11-16 09:04:58 +08:00
misaka19000
2016-11-16 09:09:26 +08:00
let 这玩意是不是出自 lisp
ssehacker
2016-11-16 09:22:35 +08:00
13 楼正解,就这两点。
4641585
2016-11-16 09:31:50 +08:00
@murmur

实际用下来感觉 var 的变量提升就是一个需要注意的坑,想不到除了作为面试题还有什么场合能用得上…所以 babe 这么做也没什么不对 233
JohnLou
2016-11-16 11:31:16 +08:00
补充一下我 8 楼说的,楼主是否明白了呢,执行下下面的代码。

for(let i = 0;i < 3;i ++) {
a[i] = function () {console.log(i);}
setTimeout(function () {i = i * 1000}, 1000);
}

a[1]() // 1000
a[2]() // 2000
coldsnap
2016-11-16 11:31:33 +08:00
@murmur
你把楼主用 let 的语法用 babel 转了试试,通过新建一个 loop 函数的确给了 i 作用域,得到也是期望的结果;改名能避免变量提升带来的问题,这样做没问题。例如:
{ let a = 'a' } console.log(a)
会被编译成
{ var _a = 'a' } console.log(a)
你得到的结果和你在支持 let 语法的宿主环境中一样。

而且有些情况根本不需要编译,例如写 electron 和 node 。准确来说你应该说对你没区别。
SuperMild
2016-11-16 11:36:28 +08:00
自从有了 let 之后,好像提倡不要用 var 了,绝大多数情况下用 let 就够了。如果一时之间觉得比较乱,建议不要去管 var ,只管用 let 就好了,没有必要执着于两者的区别(过一段时间回头看很可能会豁然开朗)。
chnhyg
2016-11-16 11:47:51 +08:00
var 与 let
- let 是更完美的 var 。
- let 声明的变量拥有块级作用域。
- let 声明的全局变量不是全局对象的属性。
- 形如 for(let I …) 的循环在每次迭代时都为 I 创建新的绑定。
- let 声明的变量直到控制流到达该变量被定义的代码行时才会被装载,所以在到达之前使用该变量会触发错误。不可访问的这段时间变量一直处于作用域中,但是尚未装载,它们位于临时死区(Temporal Dead Zone)中。
- 用 let 重定义变量会抛出一个语法错误。
vlxer
2016-11-16 14:54:20 +08:00
要理解这个,首先要理解词法作用域。

* 定义一个函数的时候,函数会保存当前作用域
* 函数执行的时候,会创建一个新的作用域,用于存放函数参数和局部变量,同时新的作用域指向函数保存的作用域,构成作用域链

因此,第一个例子中,由于没有块级作用域,循环里的所有函数都是共享同一个作用域的, a[0] == a[1] == ... == a[9] == i == 10 。

第二个例子中,有块级作用域,等价于:

```js
var a = [];
for (var i = 0; i < 10; i++) {
(function(i) {
a[i] = function() {
console.log(i);
};
})(i);
}
a[6](); // 6
```

通过查看 babel 的转换也可以看出:
http://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=latest%2Creact%2Cstage-2&experimental=false&loose=false&spec=false&code=var%20a%20%3D%20%5B%5D%3B%0Afor%20(let%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20a%5Bi%5D%20%3D%20function%20()%20%7B%0A%20%20%20%20console.log(i)%3B%0A%20%20%7D%3B%0A%7D%0Aa%5B6%5D()%3B%20%2F%2F%206&playground=true

不明白问我,付费指导。
anthozoan77
2016-11-28 22:47:32 +08:00
IIFE

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/320790

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX