es6之前
关于变量提升这一定义,MDN种是这样说的
变量提升(Hoisting)被认为是, Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。在 ECMAScript® 2015 Language Specification 之前的JavaScript文档中找不到变量提升(Hoisting)这个词。
从概念的字面意义上说,“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。
在es6之前,只有var关键字,不管变量在哪里定义的都会提升到作用域的顶端(确切来说在es6之前JavaScript只有全局作用域跟函数作用域)
console.log(a); // undefined
var a = 1
被编译后大致是这样的
var a;
console.log(a);
a = 1;
除了变量的提升,方法也是一样的
fn(); // this is a function
function fn(){
console.log('this is a function');
}
需要注意的是,如果是变量接收方法,在变量赋值之前调用会报错
fn(); // TypeError: fn is not a function
var fn = ()=>{
console.log('调用啦~');
}
es6之后
在es6加入了两个声明变量的关键字let和const,并且有了块级作用域概念的出现.
块级作用域,简单来说就是用{}包裹起来的区域,包括但不限于方法、for循环、if语句甚至是单独的{}等.
在声明let或者const变量时,是不存在变量提升这一说的,并且出现了暂时性死区这一概念.
consolg.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 1; // const 定义是一样的
暂时性死区
ES6 规定:如果区块中存在 let 和 const,这个区块对这两个关键字声明的变量,从一开始就形成了封闭作用域。假如尝试在声明前去使用这类变量,就会报错。这一段会报错的区域就是暂时性死区。
注意点,在块级作用域中定义了跟外部一样的变量,可能会出现暂时性死区而报错
const a = 1;
function fn(){
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
// ...do something
const a = 2;
}
fn()
使用switch时要特别注意下
let a = 1;
let b = 1;
switch(a) {
case 1:
console.log('b is ', b); // Uncaught ReferenceError: Cannot access 'b' before initialization
break
case 2:
let b = 2;
// ... do something
break
default:
console.log('b is ', b)
break
}
尽量别在switch中声明变量,如果要声明的话请用下面这种方式
let a = 1;
let b = 1;
switch(a) {
case 1:
{
console.log('b is ', b); // b is 1
break
}
case 2:
{
let b = 2;
// ... do something
break
}
default:
console.log('b is ', b)
break
}