let 和 const 是 ES6 中新增的命令,是用於解決 ES5 中使用 var 命令聲明變量的一些問題而出現的, 在瞭解 let 和 const 以前,咱們先來簡單回看一下 var 命令的一些不合理的問題,而後再來 瞭解 let 和 const 的特性。javascript
var 主要有以下幾個不合理的地方:java
ES5 只有全局做用域和函數做用域,沒有塊級做用域。git
for(var i = 0; i<10; i++){
//...
}
console.log(i); // 輸出 10
複製代碼
對於有塊級做用域的語言來講,for 語句初始化變量的表達式所定義的變量,只會存在於循環的環境中。 而對於 ES5 中的 var 命令來講,由 for 語句建立的變量 i 即便在 for 循環結束執行後,也依舊存在於循環外部的執行環境中。github
使用 var 語句重複聲明變量是合法且無害的。安全
var a = 1;
console.log(a); //print : 1
var a = 2;
console.log(a); //print : 2
var a = 3;
console.log(a); //print : 3
複製代碼
在大多數語言中,在同一個做用域屢次聲明同一個變量是非法的,可是在 ES5 中使用 var 命令重複聲明的沒有任何問題的。數據結構
在全局做用域下經過 var 命令聲明變量,會建立一個新的全局變量做爲全局對象的屬性。函數
var a = 1;
console.log(window.a); // print: 1
複製代碼
咱們僅僅只是在全局做用域中經過 var 聲明瞭一個變量,這個變量竟然就掛載到了全局對象上, 這徹底超出了咱們的預期,是否是很不合理呢!ui
JS引擎在對代碼進行編譯解釋的時候,會查找全部經過 var 命令聲明的變量,會將建立變量的時機提高到當前做用域spa
第一個例子:指針
if( flg ){
var value = 1;
}
console.log(value);
複製代碼
初學者可能會以爲只有 flg 爲 true 的時候,纔會建立 value,若是 flg 爲 false,結果應該是報錯,然而由於變量提高的緣由,代碼至關於:
var value;
if (flg) {
value = 1;
}
console.log(value); // flg 爲true 的時候,輸出 1;flg 爲false 的時候,輸出 undefined
複製代碼
第二個例子:
console.log(tmp); // print : undefined
var tmp = 1;
console.log(tmp); // print : 1
複製代碼
初學者可能認爲咱們第一次打印 tmp 的時候應該拋出異常,由於此時 tmp 尚未聲明。 其實否則,由於 ES5 中的 var 命令存在變量提高,會將變量建立和初始化階段提高至做用域頂部, 將變量的賦值階段保留在當前位置。
爲了解決 var 所產生的種種不合理的狀況,ES6 新增了 let 和 const 命令,用於建立安全穩定易理解的變量。
ES6 中新增了塊級做用域,而且塊級做用域能夠任意嵌套
{
let a = 1;
console.log(a); // print: 1
}
console.log(a); // print error:ReferenceError: a is not defined
複製代碼
這個例子中,經過 let 命令聲明的變量 a 僅在塊級做用域內生效,因此在塊級做用域外引用變量 a 會提示未定義。
let a = 1;
const b = 1;
console.log(window.a); // print: undefined
console.log(window.b); // print: undefined
複製代碼
let 和 const 命令在全局做用域下建立變量,並不會綁定至全局對象中。
爲了糾正 var 命令會發生變量提高的現象,let 和 const 命令改變了語法行爲, let 和 const 所聲明的變量必定要在聲明後使用,不然報錯。
// var 的狀況
console.log(foo); // 輸出undefined
var foo = 2;
// let 的狀況
console.log(bar); // 報錯ReferenceError
let bar = 2;
複製代碼
上面代碼中,變量 foo 用 var 命令聲明,會發生變量提高,即腳本開始運行時,變量 foo 已經存在了,可是沒有值,因此會輸出 undefined。 變量 bar 用 let 命令聲明,不會發生變量提高。這表示在聲明它以前,變量 bar 是不存在的,這時若是用到它,就會拋出一個錯誤。
let 和 const 不容許在相同做用域內,重複聲明同一個變量。
let a = 1;
var a = 2; //print error : Identifier 'a' has already been declared
複製代碼
let a = 1;
let a = 2; // print error: Identifier 'a' has already been declared
複製代碼
在函數體中從新聲明形參,一樣報錯
function fn(params){
let params = 1;
} // print error: Identifier 'params' has already been declared
複製代碼
暫時性死區(Temporal Dead Zone),簡寫爲 TDZ。
let 和 const 聲明的變量不會被提高到做用域頂部,若是在聲明以前訪問這些變量,會致使報錯。
console.log(x); // print error: ReferenceError: value is not defined
let x = 1;
複製代碼
這是由於 JavaScript 引擎在掃描代碼發現變量聲明時,要麼將它們提高到做用域頂部(遇到 var 聲明), 要麼將聲明放在 TDZ 中(遇到 let 和 const 聲明)。 訪問 TDZ 中的變量會觸發運行時錯誤。 只有執行過變量聲明語句後,變量纔會從 TDZ 中移出,而後方可訪問。
簡單的來講,只要當前做用域內使用 let 和 const 命令建立了變量,那麼在當前做用域的開始直到變量聲明的一刻, 這個階段就叫作暫時性死區,也就是說從當前做用域的開始到變量建立的一刻,只要使用了這個變量就會報錯。
沒法使用和當前做用域內同名的外部變量
let name = 'tom';
function fn(){
console.log(name); // print error : ReferenceError: name is not defined
let name = 'jack'
}
fn();
複製代碼
typeof再也不是一個百分之百安全的操做
typeof x; // ReferenceError
let x;
複製代碼
變量 x 使用 let 命令聲明,因此在聲明前,都屬於 x 的死區,只要用到變量 x 就會報錯。
const 聲明的是一個只讀常量,一旦聲明,常量的值就不能改變。
const x = 1;
x = 2; // print error: TypeError: Assignment to constant variable.
複製代碼
const 聲明的時候必須當即初始化,不能等到之後賦值,只聲明不賦值,就會報錯。
const y; // print error:SyntaxError: Missing initializer in const declaration
複製代碼
const 實際上保證的並非變量的值不可改動,而是變量指向的內存地址所保存的數據不可變動。
對於簡單類型,值就保存在變量指向的那個內存地址,所以等同於常量。
但對於引用類型的數據,變量指向的內存地址,保存的只是一個指向實際數據的指針, const 只能保證這個指針是固定的(即老是指向另外一個固定的地址), 至於它指向的數據結構是否是可變的,就徹底不能控制了
const foo = {};
foo.prop = 123;
foo.prop // 123
foo = {}; // print error: TypeError: Assignment to constant variable.
複製代碼
上面代碼中,常量foo儲存的是一個地址,這個地址指向一個對象。 不可變的只是這個地址,即不能把foo指向另外一個地址,但對象自己是可變的,因此依然能夠爲其添加新屬性。
預計每週1-2篇文章,持續更新,歡迎各位同窗點贊+關注
後續內容參見寫做計劃
寫做不易,若是以爲稍有收穫,歡迎~點贊~關注~