总结:let和const
一:let和const共同点
1.仅在块级作用域生效
let:
for(let i=0; i<1; i++) { console.log(i)//0 } console.log(i)//报错
const:
if(true) { const max = 5; } console.log(max)//Uncaught ReferenceError: max is not defined
2.不存在变量提升
let:
console.log(foo);// 输出ReferenceError
let foo="123";
const:
console.log(foo); // 输出 foo is not defined var foo = 2;
3.不允许重复声明变量
let:
// 报错 function func() { let a = 10; var a = 1; } // 报错 function func() { let a = 10; let a = 1; } 因此,不能在函数内部重新声明参数。 function func(arg) { let arg; // 报错 } function func(arg) { { let arg; // 不报错 } }
const:
var message = "Hello!"; let age = 25; // 以下两行都会报错 const message = "Goodbye!"; const age = 30;
4.暂时性死区(只要块级作用域内存在let或者const命令,它们所命令的变量就绑定在这个区域,不再受外部的影响)
let:
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError let tmp = “456”; }
const:
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError const tmp="456"; }
ES6 明确规定,如果区块中存在let
和const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
二:let
1.特殊情况:在循环遍历中,循环变量是一个父作用域,循环体内部是一个单独的子作用域。两者并不影响。
for(let i=0; i<10;i++) { let i="abc"; console.log(i) } //abc //abc //abc
2.var和let的区别
var
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10 for(var i=0;i<10;i++){ setTimeout(function(){ console.log(i) //10(10) },1000) }
上面代码中i是var声明的,不属于 for 循环体,属于 global.等到 for 循环结束,i 已经等于10 了,然后再去执行函数里的方法。
let
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
三:const
1.const声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415; console.log(PI) // 3.1415 PI = 3; // TypeError: Assignment to constant variable.
2.const实际上保证的,并不是变量的值不能改动,而是变量指向的那个内存地址不得改动,对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const
只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
const foo = {}; // 为 foo 添加一个属性,可以成功 foo.prop = 123; foo.prop // 123 // 将 foo 指向另一个对象,就会报错 foo = {}; // TypeError: "foo" is read-only
上面代码中,常量foo
储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo
指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
如果真的想将对象冻结,应该使用Object.freeze
方法。
const foo = Object.freeze({}); // 常规模式时,下面一行不起作用; // 严格模式时,该行会报错 foo.prop = 123;
除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。
var constantize = (obj) => { Object.freeze(obj); Object.keys(obj).forEach( (key, i) => { if ( typeof obj[key] === 'object' ) { constantize( obj[key] ); } }); };