主要知識點有:var變數提升、let宣告、const宣告、let和const的比較、塊級繫結的應用場景
1. var宣告以及變數提升
變數提升:使用var
宣告變數,變數的建立並不在宣告變數的地方,而是會在當前作用域的頂部。
如果宣告在函式內,則變數的建立則會在函式作用域的頂部;如果宣告不在函式內,則會提升到全域性作用域的頂部。
示例
function getValue(condition){
if(condition){
var value = "yes";
return value;
}else{
//value 在此處可訪問,值為 undefined
return null;
}
//value 在此處可訪問,值為 undefined
}
複製程式碼
等價於(var變數提升到當前函式作用域的頂部):
function getValue(condition){
var value;
if(condition){
value = "yes";
return value;
}else{
//value 在此處可訪問,值為 undefined
return null;
}
//value 在此處可訪問,值為 undefined
}
複製程式碼
由變數提升會帶來迴圈變數過度共享的問題
2. let宣告
與var宣告變數語法一致,但是let宣告變數不會變數提升,變數的作用域只會限制在當前程式碼塊中。由於let變數並不會提升到程式碼塊的頂部,因此,要想讓整個程式碼塊能給訪問到let變數,需要將let宣告指定到程式碼塊的頂部。
示例
function getValue(condition){
if(condition){
let value = "yes";
return value;
}else{
//value 在此處不可訪問
return null;
}
//value 在此處不可訪問
}
複製程式碼
let變數禁止重複宣告:如果一個識別符號已經在程式碼塊內部中被定義,那麼使用let以同樣的識別符號宣告變數則會報錯
示例:
var count = 43;
let count; //重複宣告,報錯
複製程式碼
3. const宣告
const宣告基本變數
const宣告:使用const宣告一個常量,一旦設定之後就不能再被修改,否則會報錯。也就是說,使用const宣告變數後要立即初始化。
const type;
type='TEST'; //Uncaught SyntaxError: Missing initializer in const declaration
正確的為:
const type='TEST'
-----------------------------
const type='TEST'
type = 'DEBUG' //ObjectMethod.html:244 Uncaught TypeError: Assignment to constant variable.
複製程式碼
const宣告物件
const只會阻止變數繫結以及變數的修改,但是不會阻止物件成員變數的修改。
const person = {name:'nancy'};
person.name= 'nike';
console.log(person.name); //nike
person = {}; //Uncaught TypeError: Assignment to constant variable.
複製程式碼
4. let與const的比較
相同點
-
不存在變數提升:let與const宣告變數都不會存在變數提升,都只在塊級作用域內,如果試圖在程式碼塊外訪問let或者const變數都會報錯;
-
禁止重複宣告:如果在同一作用域內,禁止let或者const使用以被定義的識別符號宣告變數;
-
都具有暫時性死區(temporal dead zone,TDZ ):使用let或者const宣告變數,如果在宣告處之前訪問變數會報錯。在變數當前作用域的塊內,變數宣告處之前被稱之為TDZ。
-
不會覆蓋全域性物件上的屬性:let變數或者const變數會在全域性作用域上建立新的變數,但是不會繫結到全域性物件上(瀏覽器則是window物件),而var變數在全域性作用域上會繫結到全域性物件,也就是說,var全域性變數可能會無意覆蓋掉全域性物件上的一些屬性。
var RegExp = 'hello'; console.log(window.RegExp); //hello console.log(window.RegExp===RegExp); //RegExp覆蓋掉window物件中的RegExp屬性 ------------- let RegExp = 'hello'; console.log(window.RegExp); console.log(window.RegExp===RegExp); //false function getValue(condition){ if(condition){ //value的TDZ let value = "yes"; return value; }else{ return value; } } 複製程式碼
不同點
- const不能再賦值,let宣告的變數可以重複賦值;
5. 塊級繫結的使用場景
-
迴圈內的let宣告
在迴圈中使用var變數,由於var變數存在變數提升,每次迭代共享同一個var變數。
for(var i = 0;i<5;i++){ setTimeout(()=>{ console.log(i); //輸出5 },1000); } console.log(i); //輸出5 複製程式碼
解決方法:將var變數改為let變數
//將var改成let之後 for(let i = 0; i < 5; i++) { setTimeout(() => { console.log(i) // 0,1,2,3,4 }, 0) } console.log(i)//Uncaught ReferenceError: i is not defined i無法汙染外部函式 複製程式碼
let變數不會變數提升,let變數作用域不會逃離出for迴圈外,因此不會汙染外部函式。而在for迴圈中也不會每次迭代都共享同一變數,而是會分別使用let變數副本。
-
迴圈內const宣告
在普通的for迴圈中使用const變數,由於const變數不可修改,因此會報錯。而在for-in或者for-of迴圈中可以使用const變數。
let arr = [1,2,3,4]; for(const item of arr){ console.log(item); //輸出1,2,3,4 } 複製程式碼
6. 總結
- let和const變數都不會進行提升,並且只會在宣告它們的程式碼塊內部存在。由於變數能夠在必要位置被準確宣告,其表現更加接近其他語言;
- 塊級繫結存在暫時性死區(TDZ ) ,試圖在宣告位置之前訪問它就會導致錯誤;
- let 與 const 的表現在很多情況下都相似於 var ,然而在迴圈中就不是這樣。在 for-in 與 for-of 迴圈中, let 與 const 都能在每一次迭代時建立一個新的繫結,這意味著在迴圈體內建立的函式可以使用當前迭代所繫結的迴圈變數值(而不是像使用 var 那樣,共享同一變數值)。同時在基礎的for迴圈中,使用const變數會出錯。
最佳實踐:在預設情況下使用 const ,而只在你知道變數值需要被更改的情況下才使用 let 。