ES6 let&const
今天來總結一下ES6裡面let與const的用法
先總體看一下ES6中的let都有哪些特性:
let 特性
- let宣告的變數在js中不可以重複宣告,防止變數的汙染和覆蓋
- let宣告的變數不涉及變數的提升,可以有效防止閉包問題
- let宣告的變數在塊級作用域中有效
- let宣告的變數存在暫時性死區
宣告的變數在為執行到宣告語句時,變數將會暫存在暫時性死區中,當執行完宣告 語句時,將會從暫時性死區中將變數取出
1. 同名變數不可以重複宣告2. let宣告的變數不存在變數提升的問題
1 var a = 100;
2 et b = 20; // 報錯
2. let宣告的變數不存在變數提升的問題
1 /** 2 * es6新出的變數定義方式宣告的變數不再與全域性物件相關聯 3 * 即class , let , const , import 宣告的變數不會把變數掛到全域性物件上 4 **/ 5 let num = 10; 6 console.log(window.num); //undefined 7 var num2 = 10; 8 console.log(window.num2); //10
我們都知道,js在全域性中宣告變數,其實質是哪個就是將該變數掛載到window物件的屬性上,因此,在訪問全域性變數時,與訪問window物件的屬性是一致的。js的設計者逐漸意識到設計存在問題,因此,逐漸開始全域性物件與全域性變數進行分離。在使用let或者const,甚至之後的class宣告變數,都不再將全域性變數掛載全域性物件(window或者global上)
3. 在ES6中還引入了塊級作用域的概念。
使用let和const宣告的變數只在申明語句所在的塊級作用域有效。離開了塊級作用域,變數的宣告失效,因此也不存在變數的提升。
1 { 2 var a = 100; 3 let b = 200; 4 } 5 6 console.log(a); // 100 7 console.log(b); // b is not defined
使用let和const+塊級作用域的宣告方式可以在某種程度上代替立即執行函式的方式
1 let vari = 123; 2 // 立即執行函式解決變數命名衝突問題 3 (function(){ 4 let vari = 456;5 console.log(vari); // 4561 6 }()) 7 8 // 塊級作用域解決變數重名問題 9 { 10 let vari = 789 11 console.log(vari); // 789 12 } 13 console.log(vari); // 123
很顯然,利用ES6的塊級作用域解決命名衝突更加簡潔明瞭。
4.暫時性死區。
1 let a = 10; 2 { 3 // 使用let宣告變數時,變數會存放在暫時性死區中,在執行宣告語句之前不可以使用該變數 4 // 即使全域性中有a變數也不行 5 console.log(a); // a is not defined 6 let a = 5; 7 }
以上的程式碼在其他程式語言中是不會報錯的,但是在js中就會報錯。雖然在全域性聲明瞭變數a,但在塊級作用域中,存在let的宣告語句,變數將會被存放在暫時性死區中。存放在暫時性死區中的變數,只有在執行了變數的宣告語句之後才會從暫時性死區中取出使用。
5.函式宣告方式
1 { 2 /** 3 * 1. 在塊級作用域內允許宣告函式 4 * 2. 函式宣告類似於var宣告,將變數宣告提升到函式作用域或者全域性作用域前面,但函式體不提升 5 * 3. 函式宣告提升到所在塊級作用域的頭部 6 **/ 7 function f() { console.log('i am in outside!'); } 8 (function () { 9 // f(); //f is not a function ,說明函式的宣告提升到了函式作用域的頭部,在此處已有f變數的宣告,其值為undefined 10 // console.log(f); 11 if (true) { 12 // f = 10; 13 console.log(f); //此處f的值為函式體,說明函式整體提升到了塊級作用域的頭部 14 // f = 10; 15 function f() { console.log('i am in inside!'); } 16 } 17 }()); 18 }
在塊級作用域中允許申明函式,不過該宣告方式與ES5的形式不同,在ES6的塊級作用域中宣告函式,會將函式的宣告部分提升到塊級作用域的頭部,而函式提不提升。
關於const的用法,其宣告特性與let一致,只不過const宣告的一般型別變數值是不可以修改的,對於引用資料型別來說是可以修改的。const宣告的實質是const宣告的物件的棧記憶體空間不能再改變,而引用變數所指向的堆記憶體空間是可以改變的。
1 { 2 let obj = { 3 name: 'zhang', 4 age: 18, 5 birthday: { 6 year: 2018, 7 month: 13, 8 day: 32 9 } 10 }; 11 let myFreeze = (obj) => { 12 for (let prop in obj) { 13 // Object.freeze()方法能夠是物件屬性的值不可改,相當於加上了const宣告 14 Object.freeze(obj); 15 // 若物件的屬性依舊是引用型別,則遞迴處理 16 if (typeof (obj[prop]) === 'object') { 17 // console.log('referencing prop'); 18 myFreeze(obj[prop]); 19 } 20 } 21 return obj; 22 } 23 var constObj = myFreeze(obj); 24 console.log(obj); 25 obj.birthday.year = 1998; //此處修改屬性無效
用上面的遞迴方式即可將一個物件轉換為物件常量,即物件中所有的屬性,不可更改。
let與const的出現使得js的變數生命更加規範,因此,建議使用const和let的方式宣告變數。