var 、const 、let 区别
var 在 ECMAScript 所有版本中都可以使用。
let 和 const 只能在 ES6 及之后的版本中使用。
var
-
函数作用域。
-
声明未初始化时,值为
undefined
。 -
变量提升机制。
在全局作用域中或还是在局部作用域中,使用
var
关键字声明的变量,都会被提升到该作用域最顶部。
function test(status) { if (status) { var value = "person"; } else { console.log(value); } console.log(value); } test(false);
if
代码块中的var
声明的变量被提升到了函数的顶端。JS 引擎在代码预编译时,会自动将所有代码里面的
var
关键字声明的语句都提升到当前作用域的顶端。// 上面的代码被解析如下 function test(status) { var value; if (status) { value = "person"; } else { console.log(value); // undefined } console.log(value); // undefined } test(false);
- 块级声明:
- 只在当前函数下声明的变量有效。
- 在代码块和{}括号之内有效。
let
-
块级声明,没有变量提升。
function test(status) { if (status) { let value = "person"; } else { console.log(value); // 报错 } console.log(value); // 报错 } test(false);
-
不允许同一个块级作用域中出现冗余声明。
如果在同一个作用域中某个变量已经存在,再次使用let关键字声明会报错。
var value = "test1"; let value = "test1"; // SyntaxError
const
-
const 声明指常量,一旦定义就不能修改。
-
常量必须初始化值,如果不初始化就会报错。
const test; // error:Missing initializer
-
const 声明对象。
const 变量不能修改指针,但可以修改值。
const obj = { name: "person", age: 21 } obj.name = "Danny"; // 没问题 obj = {}; // error:不能修改对象指针
暂时性死区
console.log(typeof value); // error:Cannot access 'value' before initialization
let value = "person";
此时的 value 还处在 JS 所谓的暂时性死区(TDZ)。
声明之前的执行瞬间被称作暂时性死区。
**工作原理:**JS 引擎在扫描代码时发现变量声明时,如果遇到var
会将他们提升到当前作用域的顶端,遇到let
或const
就会将声明放到 TDZ 中,如果访问 TDZ 中的变量就会抛出错误,只有执行完 TDZ 中的变量才会将它移出,然后就可以正常访问。这种机制只会在当前作用域生效。
在不同作用域下:【此处有待深究学习】
console.log(typeof value); // undefined
if(true) {
let value = "person";
}
三者最大区别
- var 在全局作用域声明的变量有一种行为会挂在 window 对象上,它会创建一个新的全局变量作为全局对象的书信,这种行为可能会覆盖到 window 对象上的某个属性。
let
和const
则不会。
var value1 = "test1";
let value2 = "test2";
const value3 = "test3";
console.log(window.value1);
console.log(window.value2); // undefined
console.log(window.value3); // undefiend
for 循环中的运用
var
声明的变量没有块级作用域,迭代变量i
会渗透到循环体外部。
for (var i = 0; i < 4; i ++) {
// ...
}
console.log(i); // 4
let
声明的迭代变量,作用域限制为 for 循环块内部。
for (let i = 0; i < 4; i ++) {
// ...
}
console.log(i); // error
真题
for (var i = 0; i < 4; i ++) {
setTimeout( () => {
console.log(i);
}, 0)
}
// 4 4 4 4
setTimeout 异步执行,for 循环退出时 i 为 4.【深究学习】
for (let i = 0; i < 4; i ++) {
setTimeout( () => {
console.log(i);
}, 0)
}
// 0 1 2 3
JS 引擎在后台会为每个迭代循环声明一个新的迭代变量,每个 setTimeout 引用的都是不同的变量实例。
总结
var
声明的范围是函数作用域,let
声明的范围是块级作用域。var
声明的变量会被提升到函数作用域的顶部,let
和const
声明的变量不存在提升,且具有暂时性死区特征。var
允许在同一个作用域中重复声明同一个变量,let
和const
不允许。- 在全局作用域中,
var
声明的变量会被挂在为 window 对象的属性,let
和const
不会。 const
行为基本与let
相同,但const
声明的变量必须进行初始化,且不能修改。