为什么ES6不鼓励用var声明变量了
在函数作用域或全局作用域中通过关键字var声明的变量,无论实际上是在哪里声明的,都会被当成是在当前作用域顶部声明的变量。
- 举个栗子:
function getValue(condition){
if(condition){
var value = "blue";
return value;
}
else{
return null;
}
}
这段代码按正常的眼光来看待,只有当condition的值为true的时候,变量value才会被创建,但是实际上,无论condition的值是什么,变量value都会被创建。在预编译阶段,JavaScript引擎会将上面的代码修改成这样。
function getValue(condition){
var value;
if(condition){
value = "blue";
return value;
}
else{
return null;
}
}
正如我在开头所说的那样,变量value 的声明被提升到了函数的顶部,但是赋值操作却依然在原处执行,这也就意味着,在else字句里,value变量也是能被访问到的,但是因为没有赋值,所以得到的结果是undefined。
这个机制被称为 变量提升(Hoisting)机制。
块级声明
块级声明用于声明在指定块的作用域之外无法访问的变量。块级作用域存在于:
- 函数内部
- 块中1
简单来说就是用块级声明所声明的变量只能在该代码块中发挥作用。
let声明
let声明是块级声明,let声明在用法上和var是一样的,用let代替var来声明变量可以把变量的作用域限制在当前代码块中。let声明是不存在变量提升机制的,因此用let声明变量时一般把声明语句放在代码块的顶部,以便整个代码块都可以访问到该变量。
举个栗子:
function getValue(condition){
if(condition){
let value = "blue";
return value;
}
else{
//变量value在这里是不存在的
return null;
}
//变量value在这里是不存在的
}
let的禁止重声明:如果作用域中已经存在某个标识符,此时再使用let来试图声明它就会报错。
举个栗子:
var a = 1;
let a = 2;
此时let不会给a赋值为2,而是会抛出错误,因为在一个作用域中不能用let重复定义已经存在的标识符。
var a = 1;
if(condition){
let a = 2;
}
这样声明变量是不会报错的,因为它们不在同一个作用域中,所以不存在重声明的问题。
const声明
const声明是块级声明,使用const声明得到的不是变量而是常量,其值被初始化之后就不可以更改,这也意味着使用const声明常量必须进行初始化操作,如果用const声明常量时没有赋值将会抛出语法错误。
举个栗子:
const my_name = "炒米粉";
//语法错误,常量未初始化。
const my_age;
//语法错误,常量的值不能被改变
my_name = "炒河粉";
值得一提的是,const也是禁止重声明的,这点与let一致,这里就不赘述了。
用const声明对象:用const来声明对象的话是不允许修改绑定关系的,但是允许修改对象的属性值。
举个栗子:
const boy = {
name:"炒米粉"
};
//修改对象属性的值是没有问题的
boy.name = "帅气的炒米粉";
//抛出语法错误
boy = {
name:"帅气的炒米粉"
};
临时死区(Temporal Dead Zone)
JavaScript引擎在扫描代码发现声明的时候,要么将声明提升到作用域顶部(var的变量提升机制),要么将声明放入TDZ中(遇到let或const)。
访问TDZ中的变量将会抛出错误,当执行过变量声明语句后,该变量才会从TDZ中移出。
举个栗子:
//num的TDZ起点
console.log("DO SOMETHING");
console.log(typeof num);
//num的TDZ终点
let num = 1;
上面的代码是会报错的,因为第二行代码仍处于num的TDZ中,却访问了num。
上面的栗子用的是let,如果换成const结果也是一样的。
相比上面的代码,这一段反而不会报错:
console.log(typeof num);//"undefined"
if(condition){
let num = 1;
}
因为第一行代码是试图访问当前作用域中并不存在的变量,所以得到的是undefined,而不会报错。
块的定义:在字符 { 和 } 之间的区域 ↩︎