let 与 var的区别
-
let有块级作用域
es5中有全局作用域、函数作用域,es6中新增了块级作用域,即用let声明的变量只能在声明的{}内访问到
// let有块级作用域
for(var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i) //打印 3个 3
}, 1000)
}
for(let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i) //打印 0 1 2
}, 1000)
}
var tmp = new Date();
function f() {
// 变量提升会执行,var没有块级作用域,变量赋值未执行
console.log(tmp);
if (false) {
var tmp = 'hello world';
}}
f(); // undefined
- 实践:
利用这个特性,在为DOM元素数组循环添加click事件时,可以用let获取需要的i
// 添加onclick事件
const dom = [{}, {}, {}]
for(let i = 0; i < 3; i++) {
dom[i].onclick = function () {
console.log(i)
}
}
dom[0].onclick() // 0
dom[1].onclick() // 1
dom[2].onclick() // 2
- for中( )的特殊块级作用域:
for循环中的()是一个特殊的块级作用域,for循环中()中的let与{}内的不冲突
for(let i = 0; i < 3; i++) {
let i = 'foo';
console.log(i); // 打印3次 foo, ()内外层作用域,{}为内层作用域,互不影响
}
// for可看成如下的代码过程,可看出内外层i互不影响
// {
// let i = 0;
// if(i < 3) {
// let i = 'foo';
// console.log(i);
// }
// i++;
// ......
// }
-
let 没有变量提升
在使用let定义变量前访问变量出错 而不是 undefined
// let 没有变量提升
console.log(b); // undefined
var b = 200;
console.log(a);
let a = 100; // Cannot access 'a' before initialization
- 在全局作用域中let声明不会像var一样会在全局window对象中创建一个属性
const
- 在let的基础上“只读”,声明后无法修改(不允许修改内存地址,例如object可以修改其内容,但不能将其指向一个新的地址)
tips: 如果要确保引用类型值的属性值不可变,请使用Object.freeze()冻结
// 将对象彻底冻结的函数
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, i) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
- 由于其声明后无法修改,因此声明的时候必须赋值 const a; a = 10;这样会报错
最佳实践
不用var,尽量用const,配合用let