ES6学习 —— let命令

本文是学习阮一峰《ECMAScript 6 入门》 let 命令部分的笔记。

基本用法

let 命令,用来声明变量,用法类似于 var ,但是所声明的变量,只在 let 命令所在的代码快内有效;

1
2
3
4
5
6
{
let a = 10;
var b = 2;
}
a // ReferenceError: a is not defined
b // 2

let命令在for循环中的应用

a. for循环的计数器

1
2
3
4
for(let i = 0; i < 10; i ++){
// ……
}
console.log(i); // ReferenceError: i is not defined

计数器 i 只在 for 循环内有效,在循环外引用就会报错。

b. for循环内声明的变量

1
2
3
4
5
6
7
var a = [];
for(let i = 0; i < 10; i ++){
a[i] = function(){
console.log(i);
}
}
a[6](); // 6

变量 ilet 声明的,当前的 i 只在本轮循环中有效,所以每次循环的 i 其实就是一个新的变量。而 JavavScript 引擎内部会记住上一轮循环的值,初始化本轮的变量 i 时,就会在上一轮循环的基础上进行计算,所以最后输出的结果是 6

c. for 循环的父作用域和子作用域
for 循环有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

1
2
3
4
5
6
7
for(let i = 0; i < 10; i ++){
let i = "abc";
console.log(i);
}
// abc
// abc
// abc

以上代码运行结果输出三次 “abc”, 这表明函数内部的变量 i 与循环变量 i 不在同一个作用域,有各自单独的作用域。

不存在变量提升

“变量提升”: 变量可以在声明之前使用,值为undefined。—— var 命令

let 命令:规定声明的变量一定要在声明后使用,否则报错。

1
2
3
4
5
console.log(a); // undefined
var a = 10;
console.log(b); // ReferenceError: b is not defined
let b = 20;

暂时性死区

在代码块内,使用 let 命令声明变量之前,该变量就是不可用的。这在语法上,称为 “暂时性死区”(temporal dead zone,简称TDZ)

只要块级作用与内存在 let 命令,它所声明的变量就 “绑定” 在这个区域,不再受外部的影响。

1
2
3
4
5
6
7
8
9
10
11
var tmp = 123; // 声明了一个全局变量
if(true){
tmp = "abc"; // ReferenceError: tmp is not defined
console.log(tmp); // ReferenceError: tmp is not defined
let tmp;
console.log(tmp); // undefined
tmp = "efd";
console.log(tmp); // efd
}

上面代码中,一开始声明了一个全局变量 tmp,但是块级作用域内 let 又声明了一个局部变量 tmp,导致 tmp 变量绑定在这个块级作用域内。

所以,块级作用域内,在 let 声明变量之前,都属于 tmp 变量的 “暂时性死区”,会报错。

typeof不再百分之百安全

1
2
3
4
typeof x; //ReferenceError: x is not defined
let x;
typeof y; // "undefined"

变量 x 使用 let 命令声明,所以在声明之前,都属于变量 x 的“暂时性死区”,只要用到变量 x 就会报错。而变量 y 没有被声明,使用 typeof 反而不会报错,返回“undefined”

隐蔽的“暂时性死区”

1
2
3
4
5
6
7
8
9
function test0(x = y, y = 2){
return [x, y];
}
test0(); // ReferenceError: y is not defined
function test1(x = 2, y = x){
return [x, y];
}
test1(); // [2, 2]

第一个函数 test0 中,调用时候报错的原因是:参数 x 默认值等于另外一个参数 y ,而此时 y 还没有声明,属于“死区”。如果 y 的默认值是 x ,就不会报错,因为此时 x 已经声明了。

第二个函数 test1 中,参数 x 的默认值为 2 ,参数 y 的默认值等于参数 x ,而此时 x 已经声明了,所以不会报错。

1
2
var x = x; // 不报错
let y = y; // ReferenceError: y is not defined

ES6规定暂时性死区和 letconst语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明之前就使用这个变量,从而导致意料之外的行为。

暂时性死区的本质: 只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

不允许重复声明

let 不允许在相同的作用域内,重复声明同一个变量。(在函数内不能重复声明参数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 报错
function(){
let a = 10;
var a = 1;
}
//报错
function(){
let a = 10;
let a = 1;
}
function fun(arg){
let arg; // 报错,不能在函数内重复声明参数
}
function fun(arg){
{
let arg; //不报错,因为不在同一个作用域内
}
}

现在与前面 for 循环的父作用域和子作用域进行对比

1
2
3
4
5
6
7
for(let i = 0; i < 10; i ++){
let i = "abc";
console.log(i);
}
// abc
// abc
// abc

这两个变量 i 虽然是在同一次循环当中,但他们的作用域不同,计数器 i 位于父作用域,而循环体内部的变量 i 位于子作用域,所以这里不会报错。(千万不要以为这也是在同一个作用域内重复声明变量)

您的支持将鼓励我继续创作!