1.let 和 const
let
1.不存在變量提升(什麼是變量提升)
console.log(carName)
// 在這裏可以使用 carName 變量,不報錯
var carName;
console.log(carName)
// 在這裏不可以使用 carName 變量,報錯
let carName;
2.同一個作用域下不能重複定義同一個名稱
var a=0;
var a=1; //不報錯,a爲1
let a= 0;
let a=1 //報錯
3.有塊級作用域,var只有函數作用域
{
let a = 10;
var b = 1;
}
a // 報錯,所在作用域未聲明a
b // 1
4.暫時性死區
只要塊級作用域內存在let命令,它所聲明的變量就“綁定”(binding)這個區域,不再受外部的影響。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp; //只要代碼塊let了一個變量,
//那這個變量就不能在被let之前使用
}
有些“死區”比較隱蔽,不太容易發現。
function bar(x = y, y = 2) {
return [x, y];
}
bar(); // 報錯
個人猜測相當於
function bar() {
let x = y;
let y = 2;
return [x, y];
}
bar(); // 報錯
5.爲什麼需要塊級作用域
第一種場景,內層變量可能會覆蓋外層變量。
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
第二種場景,用來計數的循環變量泄露爲全局變量。
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
使用let的話, i 便是塊級作用域的變量,外層作用域無法使用
ES6 的塊級作用域必須有大括號,如果沒有大括號,JavaScript 引擎就認爲不存在塊級作用域。
// 第一種寫法,報錯
if (true) let x = 1;
// 第二種寫法,不報錯
if (true) {
let x = 1;
}
const
let的特性const基本都有,不同的是
const聲明一個只讀的常量。一旦聲明,常量的值就不能改變。
const PI = 3.1415;
PI // 3.1415
PI = 3;//報錯
const實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址不得改動。
const foo = {};
// 爲 foo 添加一個屬性,可以成功
foo.prop = 123;
foo.prop // 123
// 將 foo 指向另一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only
如果真的想將對象凍結,應該使用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] );
}
});
};
var命令和function命令聲明的全局變量,依舊是頂層對象(window)的屬性;另一方面規定,let命令、const命令、class命令聲明的全局變量,不屬於頂層對象的屬性。