声明提前
在js中存在一种机制,在程序正式执行之前,会将var声明的变量和function声明的函数预读到当前作用域的顶部,这就是变量提升和函数提升,这种机制也可以称为变量提升。
例如:
function a(){console.log(10);}a(); //20function a(){console.log(20);}a(); //20
本意是想通过这个函数分别打印输出10和20,但是由于声明提前,后一个a函数将前面第一个a函数覆盖,导致10无法输出,更要注意的是函数的声明提前是整体提前,而变量只是把声明给提前了,所以为了解决这种全局作用域弊病的问题,建议采用let或const来代替var(let、const是块级作用域),或者采用闭包来解决。<br />通常JS引擎会在正式执行前进行一次“预编译”,就是将变量声明和函数声明提升至当前作用域的顶端,然后再执行。下面将具体介绍JavaScript中的变量提升与函数提升。
console.log(a); // undefinedconsole.log(fn); // fn(){var b = 2}console.log(b); // Uncaught ReferenceError: b is not definedvar a = 1;function fn() {var b = 2;};
在预编译之后的代码逻辑如下:
//预编译之后function fn(){var b = 2;}var a;console.log(a);console.log(fn);console.log(b);a = 1;
声明提前优先级
“函数会首先被提升,然后才是变量。”——《你不知道的JavaScript》
console.log(foo);function foo(){console.log("函数声明");}var foo = "变量";/* 输出为:function foo(){console.log("函数声明");} */
预编译之后的实际情况:
function foo(){console.log("函数声明");}var fooconsole.log(foo);foo = "变量";
函数提升优先级⽐变量提升要⾼,且不会被变量声明覆盖,但是会被变量赋值覆盖。
暂时性死区
ES6规定,如果在区块中存在let和const命令(class也有暂时性死区),这个区块对这些命令声明的变量,从这个区块的一开始到它声明之前的这块区域形成了封闭作用域,凡是在这之间(声明之前)使用了这些变量,就会报错。即使用了let或const声明的变量之前,这些变量都是不可用的。这就成为“暂时性死区”。
例如:
var a = 10;if (true) {//变量a的暂时性死区 startconsole.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization//变量a的暂时性死区 endlet a = 20;}
