var
-
var是js最早引入的用于声明变量的关键字,在 ES6 之前一直被广泛使用。 -
var声明的变量具有函数级作用域,在函数体内可见。 -
存在变量提升特性。
function varFun() {
if(true) {
var x = 10;
}
console.log(x); // 输出 10,因为 var 声明的变量是函数级作用域
}
varFun();
console.log(x); // 输出 undefined
var x = 10;
// 以上代码等价于下面的代码
var x;
console.log(x);
x = 5
let
-
let是ES6引入的块级作用域变量声明关键字,解决了var在作用域方面的一些问题。 -
let声明的变量具有块级作用域,只在离定义最近的{}中才可见。 -
不存在变量提升特性。
-
同一作用域中不允许重复命名(报错),但能够重新赋值。
function letFun() {
if(true) {
let y = 20;
}
console.log(y); // 报错,y 在{}外不可见
}
letFun();
const
const也是ES6引入的关键字,用于声明常量,一旦被赋值就不能再修改其值。const声明的常量是块级作用域,类似let。- 与
let不同的是,const声明的变量必须在声明时赋值,且后续不可以重新赋值。
function constFun() {
const z = 30;
// z = 40; // 报错, 无法重新赋值
console.log(z);
}
constFun();
总结:
-
开发中尽量使用
let代替var声明变量,因为块级作用域可以让变量的声明更加可控:- 只有在当前块中可见,在不同块中就算使用了相同名称的变量也不会有所干扰,但是如果在同一个函数的不同块中用
var声明变量,名称相同,就可能发生覆盖或逻辑混乱。 let声明的变量在块级作用域结束时会被销毁,从而释放内存,可以避免内存泄漏和不必要的变量持久化。
- 只有在当前块中可见,在不同块中就算使用了相同名称的变量也不会有所干扰,但是如果在同一个函数的不同块中用
-
如果需要声明一个可以重新赋值的变量,使用
let;如果需要声明一个不可变的常量,使用const。
拓展
从词法环境和变量环境理解变量提升
console.log(x); // undefined
var x = 5;
console.log(y); // 报错: y 未初始化
let y = 10;
console.log(z); // 报错: z 未初始化
const z = 15;
预编译代码如下:
GlobalExecutionContent = { // 全局上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 词法环境的环境记录
Type: "Object",
y: <uninitialized>, // let声明,未初始化
z: <uninitialized>, // const声明,未初始化
// 剩余标识符
},
Outer: null, // 词法环境的外部环境引用,因为当前为全局上下文,所以没有外部环境
},
VariableEnvironment: { // 变量环境
EnvironmentRecord: { // 变量环境的环境记录
Type: "Object",
x: undefined,
// 剩余标识符
},
Outer: null, // 变量环境的外部环境引用,因为当前为全局上下文,所以没有外部环境
}
}
上面的代码在执行的时候,会创建全局上下文对象,然后再创建词法环境和变量环境,var声明的变量在变量环境中创建一开始就被赋值undefined,而let声明的变量在词法环境中创建一开始为未初始化。因此,在未给let声明的变量赋值前就对其进行访问会报错,而var则不会。