let, const, var
javascript在ES6之前是没有块级作用域的概念的,ES6引**let**,**const**关键字引入块级作用域,也称为lexical scope.
下面谈一谈let,const与var的差别。
1.在同一作用域,let,const声明之后不能重复声明
var a = 10;
var a = 20; // ok
let b = 10;
let b = 20; // error "b"已经声明了
b = 24; // ok
const c = 10;
const c = 14; // error "c"已经声明
c = 24; // error 不能对constant变量在同一作用域重复声明
{
const c = 34; // ok
}
2.变量提升(Hoisting)
**var** 经常引起问题的原因就是变量提升,因为ES5没有块级作用域的概念,let,const很好的解决了这个问题。
比如:
function getValue(isSomething) {
// value exists here
if (isSomething) {
var value = 34;
return value;
} else {
return null;
}
// value exists here
}
等同于:
function getValue(isSomething) {
var value; // 变量提升hoisting
if (isSomething) {
value = 34; // 在此处赋值
return value;
} else {
return null;
}
// value exists here
}
let,const在为声明之前是不能使用的,在同一作用域内,会出现TDZ(暂时死区),比如:
function someFunc() {
console.log(typeof value); // error, value未定义,TDZ
let value = 12;
}
3.var,let,const 在for循环中
var:
for (var i = 0; i < 10; i++) {
// ...
}
console.log(i); // 10 ,i在外面仍然可以访问,变量提升
let:
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i); // error, i未定义
const:
for (const i = 0; i < 10; i++) { // error, constant 不能改变
// ...
}
console.log(i); // error, i未定义
4.在函数循环中,闭包问题
var:
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}
funcs.forEach(function(func) {
func(); // 输出10次“10”
})
// 因为函数内部i引用外部i,形成闭包,引用的对象都为i,最后i=10,所以函数中i全部变为10
// 可以使用IIEF让每次i都返回
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push((function(value){
return function() {
console.log(value);
}
})(i));
}
funcs.forEach(function(func) {
func(); // 输出 0123456789
})
let:
var funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}
funcs.forEach(function(func) {
func(); // 输出 0123456789
})
5.let,const在for...in.., for...of...中
对于for...in, for...of 对对象属性进行遍历,var会出项变量提升的问题,const在for...in,for...of中,变量不能改变
var funcs = [];
var obj = {
a: true,
b: true
}
for (let key in obj) {
funcs.push(function() {
console.log(key);
});
}
funcs.forEach(function(func) {
func(); // "a", "b", "c"
});
6.在全局作用域下声明,let,const在全局作用域下,但是不会成为全局对象的属性
// 全局作用域
var RegExp = "hello"; // 修改了native对象
"RegExp" in window; // true
window.RegExp === RegExp // true
let RegExp = "HELLO";
"RegExp" in window; // false,没有修改原生对象,只是遮盖了原生对象
window.RegExp === RegExp // false
7.总结
- let,const不会产生变量提升,只存在其所声明的块状作用域,未声明前不能使用;
- let,const在for每次循环都会绑定一个新的值,这点和var区别要注意;
- 在全局作用域下的赋值,let,const不是直接添加到全局对象,称为全局对象的属性;
- let一般都能替代var,并且产生的效果和预期一样,const表示常量。