ES6學習(一)之var、let、const
1、變數提升
概述:變數可在宣告之前使用。
console.log(a);//正常執行,控制檯輸出 undefined var a = 1; console.log(b);//報錯,Uncaught ReferenceError: b is not defined let b = 1; console.log(c);//報錯,Uncaught ReferenceError: c is not defined const c = 1;
var 命令經常會發生變數提升現象,按照一般邏輯,變數應該在宣告之後使用才對。為了糾正這個現象,ES6 規定 let 和 const 命令不發生變數提升,使用 let 和 const 命令宣告變數之前,該變數是不可用的。主要是為了減少執行時錯誤,防止變數宣告前就使用這個變數,從而導致意料之外的行為。
2、暫時性死區
概述:如果在程式碼塊中存在 let 或 const 命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡是在宣告之前就使用這些變數,就會報錯。
var tmp = 123; if (true) { tmp = 'abc';//報錯,Uncaught ReferenceError: tmp is not defined let tmp; }
剖析暫時性死區的原理,其實let/const同樣也有提升的作用,但是和var的區別在於
- var在建立時就被初始化,並且賦值為undefined
- let/const在進入塊級作用域後,會因為提升的原因先建立,但不會被初始化 ,直到宣告語句執行的時候才被初始化,初始化的時候如果使用let宣告的變數沒有賦值,則會預設賦值為undefined,而const必須在初始化的時候賦值。而建立到初始化之間的程式碼片段就形成了暫時性死區
3、不允許重複宣告
let
不允許在相同作用域內,重複宣告同一個變數。
// 報錯 function func() { let a = 10; var a = 1; } // 報錯 function func() { let a = 10; let a = 1; } function func(arg) { let arg; } func() // 報錯 function func(arg) { { let arg; } } func() // 不報錯
4、塊級作用域
在es5中我們會遇到下面這寫情況
第一種場景,內層變數可能會覆蓋外層變數。
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world';//沒有塊級作用域tmp變數提升到函式作用域裡導致tmp為undefined } } f(); // undefined
第二種場景,用來計數的迴圈變數洩露為全域性變數。
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
上面程式碼中,變數i
只用來控制迴圈,但是迴圈結束後,它並沒有消失,洩露成了全域性變數。
let n = 5; if (true) { let n = 10; } console.log(n); // 5 }
let實際上為 JavaScript 新增了塊級作用域。
5、const注意點
1、const宣告變數的時候必須賦值,否則會報錯,同樣使用const宣告的變數被修改了也會報錯
2、const宣告變數不能改變,如果宣告的是一個引用型別,則不能改變它的記憶體地址
const c ; //Uncaught SyntaxError: Missing initializer in const declaration const a= {a:1}; a.a=2; a={d:2};// Uncaught TypeError: Assignment to constant variable.
本質 :const實際上保證的,並不是變數的值不得改動,而是變數指向的那個記憶體地址所儲存的資料不得改動。對於簡單型別的資料(數值、字串、布林值),值就儲存在變數指向的那個記憶體地址,因此等同於常量。但對於複合型別的資料(主要是物件和陣列),變數指向的記憶體地址,儲存的只是一個指向實際資料的指標,const只能保證這個指標是固定的(即總是指向另一個固定的地址),至於它指向的資料結構是不是可變的,就完全不能控制了
那麼我們想得到不可修改的const要怎麼做呢?應該使用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] ); } }); };
參考文章
ECMAScript 6 入門