乐趣区

ES6-变量和函数参数的临时死区

ES6 的第一章便是讲新增了 let 和 const 这两个变量,可以用于定义块级作用域的变量。相对于于 var 定义的变量,由 let 和 const 定义的变量作用域不会被提升。但是值得注意的是,由 let 和 const 定义的变量还拥有一个会让人恨容易犯错的特性:临时死区(Temporal Dead Zone,下文以 TDZ 简称)。但是拥有 TDZ 的不仅是变量,函数的参数也有,接下来就一一讲解。
一:变量的临时死区
例 1:在变量的作用域外引用变量

function testTdz() {console.log(colour);
    if(1 === 1){let colour = 'blue';}
}
testTdz(); //undefined

例 2:在变量的临时死区内引用变量

function testTdz() {if(1 === 1){console.log(colour);
        let colour = 'blue';
    }
}
testTDZ(); // Uncaught ReferenceError: Cannot access 'colour' before initialization

例 3: 在变量作用域且初始化之后引用变量

function testTdz() {if(1 === 1){
        let colour = 'blue';
        console.log(colour);
    }
}
testTdz();//'blue'

以上的三个例子,例 2 展示了在变量的临时死区内引用变量会导致抛出错误。再结合这三个例子我可以准确地定义出变量的临时死区的区域为:

1: 在变量的作用域内
2: 在变量的定义之前

如果以一张图来表示的话,就是下图所示,框起来的区域:

这里需要特别注意的是,我们在 if 表达式里面定义 colour 变量,那么它的作用域就只是在 if 表达式的大括号里面。在 testTdz()方法内,if 表达式大括号外的区域不是 colour 的作用域,那就一定不是它的临时死区,在这些地方引用 colour 变量,是不会造成抛错的,只是变量的值是 undefined,这也是上面的例 1 所展示的道理。

二:函数参数的临时死区
我们在定义函数参数的时候,其实在背后,这些参数就如同用 let 定义的变量一样,拥有自己的作用域。这些参数变量在初始化之前,如果被引用,也会抛出错误。当我们调用函数,会通过参数的传值或者默认值初始化这些参数。为了理解函数参数的临时死区特性,我们先来看一个正确使用函数参数的例子:
例 1:

function testFunctionTdz(first, second = first + 1) {console.log(`first: ${first} || second: ${second}`);
}
testFunctionTdz(1); //first: 1 || second: 2
testFunctionTdz(1, 1); //first: 1 || second: 1

当我们执行 testFunctionTdz(1) 的时候,实际上背后的执行代码是:

let first = 1;
let second = first + 1; // 1 + 1

当我们执行testFunctionTdz(1, 1) 的时候,实际执行的代码是:

let first = 1;
let second = 1;

所以上面的两个调用都可以正常地调用下去。接下来我们稍微改造一下上面的代码,看一个在参数的临时死区引用变量,从而导致程序抛错的例子:

function testFunctionTdz(first = second + 1, second) {console.log(`first: ${first} || second: ${second}`);
}
testFunctionTdz(1, 1); // first: 1 || second: 1
testFunctionTdz(undefined, 1); // Uncaught ReferenceError: Cannot access 'second' before initialization

在这个例子,当我们执行 testFunctionTdz(undefined, 1) 时,背后的代码实际上是:

let first = second; // 在这个区域,就是变量 second 的临时死区,所以会导致程序抛错
let second = 1;

以上就是变量和函数参数的临时死区的内容,自认为应该是讲得十分清楚了。

退出移动版