浅谈 var、let 和 const (一)
前言
ES6新增了 let 和 const 两个关键字 ,用于声明变量,这两个命令和 var 有很多不同之处,两者之间也有一些细微的差别。
let 和 const 的用法类似于 var,但是 let 只在所在的代码块内有效,所以我们一般使用 let 替代 var, 用 const 来声明常量。
声明方式 | 变量提升 | 暂时性死区 | 重复声明 | 初始值 | 作用域 |
---|---|---|---|---|---|
var | 允许 | 不存在 | 允许 | 不需要 | 除块级 |
let | 不允许 | 存在 | 不允许 | 不需要 | 块级 |
const | 不允许 | 存在 | 不允许 | 需要 | 块级 |
今天我们主要学习下块级作用域。
块级作用域
(1) ES5没有块级作用域
在ES6之前,没有块级作用域的概念,只有两种作用域,函数作用域和全局作用域。 所有的变量和函数声明都存在于这两种作用域中。
(2) 什么是块级作用域?
我找了个定义如下:
任何一对花括号中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。
举个例子
// 例子1
for(var i = 0; i < 10; i++) {
console.log(i); // 最后一次循环i=9,循环结束i++后,i=10
}
console.log(i);// 跳出 for 循环了,这里仍可以使用i变量
// 例子2
for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i)
}, 1000);
}
执行例子1时,外层 console.log 会输出10,这是因为使用var声明的变量不具备块级作用域的特性。变量 i 只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
执行例子2时,console.log 会输出10个10,这是因为 循环本身及十次 timeout 回调均共享唯一的变量 i 。当循环结束执行时,i 的值为10。
所以当第一个 timeout 执行时,调用的 i 为10。
注意:如果初始化变量时,没有使用 var声明,该变量会自动被添加到全局环境。
(3) ES5怎么创建块级作用域?
立即执行函数
“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。
想进一步了解立即执行函数,可参考学习 IIFE学习
(function() {
// 这里是块级作用域
})();
function(){…}是一个匿名函数,包围它的一对括号将其转换为一个表达式,紧跟其后的一对括号调用了这个函数。
立即执行函数也可以理解为立即调用一个匿名函数,可以用来模拟块级作用域。
(4) ES6中的块级作用域
在ES6中,我们用 let 和 const 关键字来实现块级作用域。(跨级作用域的特性,let,const是类似的,因此主要讲let)
- let声明的变量,只在所在的代码块{}内有效,在{}外不能访问(外层代码块不受内层代码块的影响)
{
let x = 1;
}
// 此处不能使用x变量,否则报错 Uncaught ReferenceError: x is not defined</pre>
for 循环中使用let,每一次循环的i其实都是一个新的变量
块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了