今天來總結一下ES6裡面let與const的用法 先總體看一下ES6中的let都有哪些特性: let 特性 1. 同名變數不可以重覆聲明2. let聲明的變數不存在變數提升的問題 2. let聲明的變數不存在變數提升的問題 我們都知道,js在全局中聲明變數,其實質是哪個就是將該變數掛載到window ...
今天來總結一下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的方式聲明變數。