本文已参与「新人创作礼」活动,一起开启掘金创作之路。
让我们来写个for循环
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 100)
}
这个代码看着好像没啥问题,我们预计的输出结果应该是 0,1,2,3,4
结果输出的居然是 5,5,5,5,5
出错了这么简单的代码居然出错了,还有天理吗?
"这里的var 应该改成 let 就可以了"一位不愿透露姓名的前端大佬路过
于是代码改成了如下:
for (let i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 100)
}
这次代码正常运行输出了0,1,2,3,4
let和var有区别么?
let和var不都是声明变量么?有啥区别?
之前的前端大佬说:"ES6规定暂时性死区和let const语句不出现变量提升,主要是为了减少运行时的错误。"
你:"能说人话不?啥暂时性死区,啥又是变量提升。不对你还没回答我let和var有啥区别呢"
大佬:"你就理解var是全局变量,let是局部变量吧"
你:"局部变量和全局变量不是通过作用域区分的么?不是看括号范围的么?"
大佬:"我们还是聊聊暂时性死区吧"
什么是暂时性死区
当程序的控制流程在新的作用域(module function 或者block作用域)进行实例化时候, 在此作用域中的let/const 声明的变量会先在作用域中被创建出来,但因此时还未进行词法绑定, 也就是对声明语句进行求值运算,所以是不能访问的,访问就会抛出错误。所以在这运行流程一旦进入作用域创建变量, 到变量开始被访问之间的一段时间,称为TDZ。
简单来说就是:
- js运行程序时首先回创建let/const声明的变量
- js在运行到let/const 的赋值运算前 let/const声明的变量不能被访问
你:一个局部变量搞这么复杂,我理解let时创建局部变量了,那为啥for循环时var和let声明的变量i会执行效果不一样呢?
大佬:"嗯,这就是变量提升的问题了"
你:能一次说完么?禁止套娃
什么是变量提升
代码执行之前,会先扫描所有域内的var声明的变量,将其先进行初始化为undefined,然后再执行代码,也就是所谓的“提升”现象。
a = 'hello'
var a
console.log(a) // 'hello'
console.log(b); // undefined 这里就是变量提升,还没声明就能用了
var b = 'word';
你: 大佬,我还是不明白为啥,var声明的和let声明的在for循环中表现不一样
大佬: 看下面的代码
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
大佬:啥效果?
你: 打印了3次 abc
大佬: 为啥?let i = ‘abc’为什么可以声明3次?,let在一个作用域内不是不能声明同名变量么?
你: 我悟了,js的每对括号就是一个作用域,所以let声明时打印的每个变量都是独立的,而var声明的是全局的,所以var声明的变量打印出来就是一样的
写在最后
js真的是一门神奇的语言,千万别尝试用编译语言的逻辑去理解解释语言的逻辑。不过js真的很方便 ES6入门教程,拿去吧,打开新世界的大门!