关于let的杂谈
一.块级作用域
先来看段代码
{
let a=1
}
console.log(a); //出错, not defined
{
var a=1
}
console.log(a); //1
var myList = document.querySelectorAll('li')
for( let i=0; i<liList.length; i++){
myList[i].onclick = function(){
console.log(i)
}
}//依次点击会依次输出 1 2 3 4 5
在ES6之前,js中只存在全局作用域和函数作用域,想要模拟块级作用域一般是采用IIFE的写法,在推出ES6后执行起来便简便许多。上述便是两个简单的例子,说明let 声明的变量的作用域是块级的。
二.let 是否存在变量提升
在此之前,让我们来看几个代码段落
console.log(a);// undefined
var a=1;
console.log(a);// Uncaught ReferenceError: Cannot access 'a' before initialization
let a=1;
console.log(a);//Uncaught ReferenceError: a is not defined
我们可以逐步分析,首先第一段代码,我们明白var关键字存在变量声明提升,等效于如下代码
var a;
console.log(a);// undefined
a=1;
输出undefined合情合理,让我有些疑惑的是后面两段代码。
如果说不存在变量声明提升,那当执行到console.log语句时a应该都是not defined才对,为何变成了Cannot access ‘a’ before initialization(初始化前无法访问“a”)。在查阅文档及博客后,我了解到了一个新的知识点:
要搞清楚提升的本质,需要理解 JS 变量的「创建create、初始化initialize 和赋值assign」
有的地方把创建说成是声明(declare),为了将这个概念与变量声明区别开,我故意不使用声明这个字眼。
有的地方把初始化叫做绑定(binding),但我感觉这个词不如初始化形象。
我们来看看 let 声明的「创建、初始化和赋值」过程
依次分析一下执行步骤
1.找到所有用 let 声明的变量,在环境中「创建」这些变量
2.开始执行代码(注意现在还没有初始化)
3.没有初始化,所以报的错为初始化前无法访问“a”
4.var的创建及初始化过程都被提升,默认为undefined
总的来说
let 的「创建」过程被提升了,但是初始化没有提升。
var 的「创建」和「初始化」都被提升了。
function 的「创建」「初始化」和「赋值」都被提升了。
所谓暂时死区,就是不能在初始化之前,使用变量。