题目:var
let
const
之间的区别
题解:
三个关键词都是用来声明变量的,其中var
在ECMAScript所有版本中都可以使用,而const
和let
只能在ECMAScript6及更晚的版本中使用。
var
vs let
-
声明作用域
使用
var
操作符声明的变量作用域是包含该变量的函数,该变量将在函数退出时被销毁。
使用let
操作符声明的变量作用域是包含该变量的块作用域,块作用域直观理解就是{}
包裹的代码块。函数作用域也可以理解为一个块作用域,因此适用于var
的作用域限制也同样适用于let
。 -
声明提升
使用
var
声明的变量会自动提升到函数作用域顶部:function foo() { console.log(age); var age = 26; } foo(); // undefined
以上代码等同于:
function foo() { var age; console.log(age); age = 26; } foo(); // undefined
而
let
声明的变量却没有这个“特权”,不会被提升到作用域顶部。JavaScript引擎在解析代码时会察觉本作用域内有let
,在let
声明变量执行之前的这段过程被称为“暂时性死区”,凡是在此阶段引用let
声明的变量都会抛出ReferenceError
。 -
变量重复声明
var
可以在作用域内重复声明,但let
不允许同一个块作用域中出现重复声明,即使是用var
声明的变量。一个变量名只允许我let
独享,就是这么霸道:var obj0; var obj0; // 不会报错 var obj1; let obj1; // SyntaxError: Identifier 'obj1' has already been declared let obj2; var obj2; // SyntaxError: Identifier 'obj1' has already been declared
-
全局变量
let
在全局作用域中声明的变量不会像var
声明的变量一样成为window对象的属性,不过同样也会和页面共存亡。
const
vs let
两个都是在ES6版本出生的,const
与let
基本相同,唯一一个重要区别是const
声明变量时必须同时初始化,并可不能修改。注意:const
如果声明的是一个对象,那么不能更改的是对该对象的引用,也就是不能重新指向其他变量,但是修改对象内部属性const
是管不着的。
const obj1 = {a: 1};
obj1.b = 2; // 不会报错
obj1 = {a: 1, b:2}; // TypeError: Assignment to constant variable.
衍生题
问:以下代码会输出什么?
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 0)
}
答:会打印出5个5,因为退出循环时变量i已经被赋值为5,执行超时逻辑时,每个回调函数都是指向那个已经变成5的i变量。
问:那么如何更改上面的代码使其挨个输出0,1,2,3,4呢?
答:只需把i的声明操作符改成let
,
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 0)
}
问:那么let是怎么做到的呢?
答:来看看babel将上一段代码转成es5后的样子:
重新定义了一个函数,在循环中调用该函数,并将i作为函数参数传进去,这样,setTimeout执行时打印的是该函数的实参,而不再是for循环里变量i。