版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/caomage/article/details/83586048
ES6(一):let和const
一、let
1. let基本用法
相當於var,但是又與var不同,因爲let聲明的變量只能在let所在的代碼塊中有效。 從以下兩段代碼以及對應的輸出結果可以很明顯的看出var與let的區別。 code:
for (var i = 0; i < 5; i++) { console.log(i); } console.log(i);
result:
0 1 2 3 4 5
code:
for (let i = 0; i < 5; i++) { console.log(i); } console.log(i);
result:
0 1 2 3 4 ReferenceError: i is not defined
2. 塊級作用域
衆所周知,在ES5中只有全局作用域和函數作用域,沒有我們所謂的塊級作用域。 這不禁讓我想起一個面試題: code:
for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(new Date, i); }, 1000); } console.log(new Date, i);
問:上面這段代碼輸出的結果是什麼? 仔細琢磨一下我們很容易得出正確的答案:
result:
2018-10-31T06:55:30.020Z 5 2018-10-31T06:55:31.021Z 5 2018-10-31T06:55:31.021Z 5 2018-10-31T06:55:31.022Z 5 2018-10-31T06:55:31.022Z 5 2018-10-31T06:55:31.022Z 5
仔細看一下發現:由於setTimeout會被JavaScript延遲執行,因此是先輸出最底部的console.log,隔一秒之後再執行循環裏面的consol.log,此時i已經全部是5。 那我們怎麼樣才能使輸出結果變成想要的0,1,2,3,4呢? 明白了let的原理之後其實問題變得很簡單: code:
for (let i = 0; i < 5; i++) { setTimeout(function() { console.log(new Date, i); }, 1000); } console.log(new Date, i);
這樣就行了嗎? result:
ReferenceError: i is not defined
哈哈,剛剛還說過let只在所在的代碼塊裏面有效,這裏最外層的console.log很明顯找不到i,所以報出引用錯誤。想要得到正確答案其實還需要去掉最後一行console.log。 當然這個題目要擱以前的話,首先想到的解決方案應該是IIFE(Immediately Invoked Function Expression:聲明即執行的函數表達式)來解決閉包造成的問題。 code:
for (var i = 0; i < 5; i++) { (function(j) { setTimeout(function() { console.log(new Date, j); }, 1000); })(i); } console.log(new Date, i);
result:
2018-10-31T07:17:45.825Z 5 2018-10-31T07:17:46.827Z 0 2018-10-31T07:17:46.827Z 1 2018-10-31T07:17:46.827Z 2 2018-10-31T07:17:46.827Z 3 2018-10-31T07:17:46.827Z 4
由此我們是不是就可以得出一個結論,有了let,我們就可以拋棄IIFE了? 這個暫時還不好說,我們還是繼續看看let的其他特性。
3. 沒有變量提升
var命令會產生變量提升的現象,這使得js這門語言變得並不嚴謹,這一點是特點也是雞肋。用var聲明的變量,如果我們在聲明之前使用,則它的值爲undefined。 而當我們用let定義變量時,就必須嚴格按照先定義再使用的原則了,反之則會拋出一個大大的引用錯誤(ReferenceError),顯然這更符合人們的使用習慣。 code:
console.log(a); var a = 2; console.log(b); let b = 2;
result:
undefined ReferenceError: b is not defined
4. 暫時性死區及不能重複聲明
ES6 明確規定,如果區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報錯。 總之,在代碼塊內,使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱爲“暫時性死區”(temporal dead zone,簡稱 TDZ)。 “暫時性死區”也意味着typeof不再是一個百分之百安全的操作。 let不允許在相同作用域內,重複聲明同一個變量。
二、const
1. const基本用法
const命令是聲明一個常量,用法和let一樣。
- 和let的相同之處是:
- const與let作用域相同,都是隻在聲明的代碼塊中起作用
- const也不會提升所聲明的常量
- const也不能重複聲明
- 不同之處是const聲明的常量在聲明時就必須賦值,因爲一旦聲明就不能改變改常量的值
2. 真的不能改變嗎?
const實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同於常量。但對於複合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指向實際數據的指針,const只能保證這個指針是固定的(即總是指向另一個固定的地址),至於它指向的數據結構是不是可變的,就完全不能控制了。因此,將一個對象聲明爲常量必須非常小心。 code&result:
const a=1; a=2;//TypeError const obj={ b:3, c:4 } obj.b=5; console.log(obj);//{b:5,c:4}
參考資料
- 《ECMAScript 6 入門》——阮一峯
- 破解前端面試(80% 應聘者不及格系列):從閉包說起——王仕軍知乎專欄:前端週刊
- ECMAScript2015官方標準