在ES6之前,我们都是用 var 关键字声明变量。无论声明在何处,都会被视为声明在函数的最顶部(不在函数内即在全局作用域的最顶部)。这就是函数变量提升 例如:
function aa() {
if(flag) {
var test = 'hello man'
} else {
console.log(test)
}
}
变量声明后代码实际上是:
function aa() {
var test // 变量提升,函数最顶部
if(flag) {
test = 'hello man'
} else {
//此处访问 test 值为 undefined
console.log(test)
}
//此处访问 test 值为 undefined
}
所以不用关心 flag 是否为 true or false。实际上,无论如何 test 都会被创建声明。
接下来ES6主角登场:
我们通常用 let 和 const 来声明,let 表示变量、const 表示常量。let 和 const 都是块级作用域。怎么理解这个块级作用域?
在一个函数内部
在一个代码块内部
只要在 {}花括号内 的代码块即可以认为 let 和 const 的作用域。
function aa() {
if(flag) {
let test = 'hello man'
} else {
//test 在此处访问不到
console.log(test)
}
}
et 的作用域是在它所在当前代码块,但不会被提升到当前函数的最顶部。
再来说说 const
const 声明的变量必须提供一个值,而且会被认为是常量,意思就是它的值被设置完成后就不能再修改了。
const name = 'cc'
name = 'yy' // 再次赋值此时会报错
还有,如果 const 的是一个对象,对象所包含的值是可以被修改的。抽象一点儿说,就是对象所指向的地址不能改变,而变量成员是可以修改的。
看以下例子就非常清楚:
const student = { name: 'cc' }
student.name = 'yy' // 修改变量成员,一点儿毛病没有
student = { name: 'yy' } // 修改变量绑定,这样子就会报错了
let
和const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let
命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区
”(temporal dead zone,简称TDZ)。
if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
typeof x; // ReferenceError
let x;
typeof undeclared_variable // "undefined"
上面代码中,在let命令声明变量tmp,x之前,都属于变量tmp,x的“死区”。只要用到该变量就会报错.
undeclared_variable是一个不存在的变量名,结果返回“undefined”。
function bar(x = y, y = 2) {
return [x, y];
}
bar(); // 报错
上面代码中,调用bar函数之所以报错(某些实现可能不报错),是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于”死区“。如果y的默认值是x,就不会报错,因为此时x已经声明了。
function bar(x = 2, y = x) {
return [x, y];
}
bar(); // [2, 2]