var,let与const

var
使用var操作符定义的变量会成为包含它的函数的局部变量。比如,使用 var在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:

function test() {
var message = "hi"; // 局部变量 
} 
test();
console.log(message); // 出错!

var操作符具有变量提升属性,使用这个定义的变量会自动提升到函数作用域顶部:

function foo() { 
console.log(age); 
var age = 26;
}
foo(); // undefined

ES运行时将其等效为:

function foo() { 
var age;
console.log(age); 
age = 26;
}
foo(); // undefined

let
let作用和var差不多,但也有很重要的区别,let声明的是块级作用域,var声明的是函数作用域:

if (true) {
var name = 'Matt'; 
console.log(name); // Matt 
} 
console.log(name); // Matt
if (true) {
let age = 26; 
console.log(age); // 26
} 
console.log(age); // ReferenceError: age 没有定义

在这里,age变量之所以不能在if块外部被引用,是因为它的作用域仅限于该块内部。块作用域是函数作用域的子集,因此适用于var的作用域限制同样也适用于let。
同时,let的声明变量不会在作用域中进行提升。在解析代码时,JavaScript引擎也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为“暂时性死区(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出ReferenceError。
const
const与let基本相同,唯一一个重要区别是用它声明的变量同时必须初始化,并且不能进行修改,const声明的限制只适用于它指向的变量的引用。换句话说,如果const变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制。
for循环中的声明
var在for循环中会渗透到循环体的外部,改成使用let之后,这个问题就消失了,因为迭代变量的作用域仅限于 for循环块内部:

for (var i = 0; i < 5; ++i) { // 循环逻辑
}
console.log(i); // 5

for (let i = 0; i < 5; ++i) { // 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义

在使用var时:

for (var i = 0; i < 5; ++i) { 
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出 0、1、2、3、4 
// 实际上会输出 5、5、5、5、5

之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5。在之后执行超时逻辑时,所有的 i都是同一个变量,因而输出的都是同一个最终值。
而在使用let声明时,js引擎会为每一次循环声明一个新的迭代变量,每个setTimeout引用的都是不同的变量实例:

for (let i = 0; i < 5; ++i) {
 setTimeout(() => console.log(i), 0)
}
// 会输出 0、1、2、3、4

虽然const变量跟let变量很相似,但是不能用const来声明迭代变量(因为迭代变量会自增):

for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务