現代JavaScript — ES6+中的Imports,Exports,Let,Const和Promise
轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。
原文出處:https://www.freecodecamp.org/news/learn-modern-javascript/
在過去幾年裡,JavaScript有很多的更新。如果你想提升寫程式碼的能力,這些更新將會對你有非常大的幫助。
對於程式設計師來說,瞭解這門語言的最新發展是非常重要的。它能使你跟上最新趨勢,提高程式碼質量,在工作中出類拔萃,從而進一步提升你的薪資待遇。
特別地,如果你想學習像React、 Angular或Vue這樣的框架,你必須掌握這些最新的特性。
最近,JavaScript增加了許多有用的功能,比如Nullish coalescing operator, optional chaining, Promises, async/await, ES6 destructuring,等等。
那麼現在,我們將探討每個JavaScript開發者都應該知道的概念。
JavaScript中的Let和const
在ES6之前,JavaScript使用var關鍵字來宣告變數,var只有全域性作用域和函式作用域,所謂全域性作用域就是在程式碼的任何位置都能訪問var宣告的變數,而函式作用域在變數宣告的當前函式內部訪問變數。此時是沒有塊級作用域的。
隨著let和const這兩個關鍵字的新增,JS增加了塊級作用域的概念。
如何在JavaScript中使用let
當我們在用let宣告變數時,用於宣告一次之後就不能再以相同的名稱重新宣告它。
1 2 3 4 5 6 7 8 9 |
|
如上所示,我們多次使用var關鍵字重新宣告瞭變數值。
在ES6之前,我們可以使用var重新宣告之前已經宣告過的變數,這就會導致了一個問題:如果我們在不知情的情況下,在其他地方重新宣告瞭該變數,很有可能會覆蓋原先變數的值,造成一些難以除錯的問題。
所以,Let解決很好地解決此問題。當你使用let重新宣告變數值時,將會報錯。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
我們發現上面的程式碼看起來沒什麼問題,是因為我們重新給value變數賦了一個新值,但是並沒有重新宣告。
我們來看下下面的程式碼:
1 2 3 4 5 6 7 |
|
如上所示,在使用var宣告變數時,可以在if塊之外訪問該變數。
而使用let宣告的number變數只能在if塊內訪問,如果在if塊外訪問將會報錯。
我們來看下接下來的程式碼
1 2 3 4 5 6 7 |
|
如上述程式碼所示,使用let分別在if塊內、if塊外宣告瞭number變數。在if塊外,number無法被訪問,因此會出現引用錯誤。
但是,如果變數number在if塊外已經宣告,將會出現下面的結果。
1 2 3 4 5 6 7 8 9 10 |
|
現在在單獨的範圍內有兩個number變數。在if塊外,number的值為20。
1 2 3 4 5 |
|
當使用var關鍵字時,i在 for迴圈之外也可以訪問到。
1 2 3 4 5 6 |
|
而使用let關鍵字時,在for迴圈外部是不可訪問的。
因此,正如上述示例程式碼所示,let宣告的變數只能在塊內部可用,而在塊外部不可訪問。
我們可以使用一對大括號建立一個塊,如下:
1 2 3 4 5 6 7 8 9 |
|
前面有提到,let在同一個塊中不能重新宣告變數,不過可以在另一個塊中重新宣告。如上程式碼所示,我們在塊內重新宣告瞭i,並賦值20,該變數僅可在該塊中使用。
在塊外,當我們列印變數時,我們得到的是10而不是之前分配的值,這是因為塊外,內部變變數i是不存在的。
如果在塊外未宣告變數,那麼將會報錯:
1 2 3 4 5 6 7 8 |
|
如何在JavaScript使用const
const關鍵字在塊級作用域中的工作方式與let關鍵字完全相同。因此,我們來看下他們的區別。
const宣告的變數為常量,其值是不能改變的。而let宣告的變數,可以為其賦一個新值,如下所示:
1 2 3 |
|
但是以下情況,我們不能這樣使用const。
1 2 |
|
我們甚至不能使用const像下面一樣重新宣告。
1 2 3 4 |
|
現在,看下面的程式碼:
1 2 3 |
|
我們說過const宣告的常量,它的值永遠不會改變——但是我們改變了上面的常量陣列並沒有報錯。這是為什麼呢?
注意:陣列是引用型別,而不是JavaScript的基本型別
實際儲存在arr中的不是陣列,而是陣列儲存的記憶體位置的引用(地址)。執行arr.push(5),並沒有改變arr指向的引用,而是改變了儲存在那個引用上的值。
物件也是如此:
1 2 3 4 5 6 7 8 |
|
這裡,我們也沒有改變obj指向的引用,而是改變了儲存在引用的值。
因此,上述的程式碼將會起作用,但下面的程式碼是無效的。
1 2 3 |
|
這樣寫會丟擲異常,因為我們試圖更改const變數指向的引用。
因此,在使用const時要記住一點:使用const宣告常量時,不能重新宣告,也不能重新賦值。如果宣告的常量是引用型別,我們可以更改儲存在引用的值。
同理,下面的程式碼也是無效的。
1 2 |
|
總結:
- 關鍵字let和const在JavaScript中新增塊級作用域。
- 當我們將一個變數宣告為let時,我們不能在同一作用域(函式或塊級作用域)中重新定義或重新宣告另一個具有相同名稱的let變數,但是我們可以重新賦值。
- 當我們將一個變數宣告為const時,我們不能在同一作用域(函式或塊級作用域)中重新定義或重新宣告具有相同名稱的另一個const變數。但是,如果變數是引用型別(如陣列或物件),我們可以更改儲存在該變數中的值。
好了,我們繼續下一個話題: promises。
JavaScript中的promises
對於很多新開發者來說,promises是JavaScript中較難理解的部分。ES6中原生提供了Promise物件,那麼Promise究竟是什麼呢?
Promise 物件代表了未來將要發生的事件,用來傳遞非同步操作的訊息。
如何創造一個promise
使用promise建構函式建立一個promise,如下所示:
1 2 3 |
|
Promise的建構函式接收一個函式作為引數,並且在內部接收兩個引數:resolve,reject。 resolve和reject引數實際上是我們可以呼叫的函式,具體取決於非同步操作的結果。
Promise 有三種狀態:
- pending: 初始狀態,不是成功或失敗狀態。
- fulfilled:表示操作成功完成。
- rejected: 表示操作失敗。
當我們建立Promise時,它處於等待的狀態。當我們呼叫resolve函式時,它將進入已完成狀態。如果呼叫reject,他將進入被拒絕狀態。
在下面的程式碼中,我們執行了一個非同步操作,也就是setTimeout,2秒後,呼叫resolve方法。
1 2 3 4 5 6 |
|
我們需要使用以下方法註冊一個回撥.then獲得1promise執行成功的結果,如下所示:
1 2 3 4 5 6 7 8 9 10 |
|
then接收一個引數,是函式,並且會拿到我們在promise中呼叫resolve時傳的的引數。
如果操作不成功,則呼叫reject函式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
如果sum不是一個數字,那麼我們呼叫帶有錯誤資訊的reject函式,否則我們呼叫resolve函式。
執行上述程式碼,輸出如下:
呼叫reject函式會丟擲一個錯誤,但是我們沒有新增用於捕獲錯誤的程式碼。
需要呼叫catch方法指定的回撥函式來捕獲並處理這個錯誤。
1 2 3 4 5 |
|
輸出如下:
所以建議大家在使用promise時加上catch方法,以此來避免程式因錯誤而停止執行。
鏈式操作
我們可以向單個promise新增多個then方法,如下所示:
1 2 3 4 5 6 7 8 9 |
|
當新增多個then方法時,前一個then方法的返回值將自動傳遞給下一個then方法。
如上圖所示,我們在第一個then方法中輸出字串,並將接收的引數result(sum)返回給下一個result。
在下一個then方法中,輸出字串,並輸出上一個then方法傳遞給它的result。
如何在JavaScript中延遲promise的執行
很多時候,我們不希望立即建立promise,而是希望在某個操作完成後再建立。
我們可以將promise封裝在一個函式中,然後從函式中返回promise,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
這樣,我們就可以通過函式將引數傳遞給promise,達到動態的目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
此外,我們只能向resolve或reject函式傳遞一個值。如果你想傳遞多個值到resolve函式,可以將它作為一個物件傳遞,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
如何在JavaScript中使用箭頭函式
上述示例程式碼中,我們使用常規的ES5語法建立了promise。但是,通常使用箭頭函式代替ES5語法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
你可以根據自己需要使用ES5或ES6語法。
ES6 Import 和Export 語法
在ES6之前,我們在一個HTML檔案中可以使用多個script標籤來引用不同的JavaScript檔案,如下所示:
1 2 3 |
|
但是如果我們在不同的JavaScript檔案中有一個同名的變數,將會出現命名衝突,你實際得到的可能並不是你期望的值。
ES6增加了模組的概念來解決這個問題。
在ES6中,我們編寫的每一個JavaScript檔案都被稱為模組。我們在每個檔案中宣告的變數和函式不能用於其他檔案,除非我們將它們從該檔案中匯出並、在另一個檔案中得到引用。
因此,在檔案中定義的函式和變數是每個檔案私有的,在匯出它們之前,不能在檔案外部訪問它們。
export有兩種型別:
- 命名匯出:在一個檔案中可以有多個命名匯出
- 預設匯出:單個檔案中只能有一個預設匯出
JavaScript中的命名匯出
如下所示,將單個變數命名匯出:
1 |
|
如果想匯出多個變數,可以使用大括號指定要輸出的一組變數。
1 2 3 |
|
需要注意的是,匯出語法不是物件語法。因此,在ES6中,不能使用鍵值對的形式匯出。
1 2 |
|
import命令接受一對大括號,裡面指定要從其他模組匯入的變數名。
1 |
|
注意,不需要在檔名中新增.js副檔名,因為預設情況下會考慮該擴充名。
1 2 3 4 |
|
提示一點,匯入的變數名必須與被匯入模組對外介面的名稱相同。
因此,匯出應使用:
1 2 |
|
那麼在匯入的時候,必須使用與匯出時相同的名稱:
1 |
|
// This will throw an error
1 |
|
如果想為輸入的變數重新命名,可以使用as關鍵字,語法如下:
1 |
|
我們以為PI重新命名為PIValue,因此不能再使用PI變數名。
匯出時也可使用下面的重新命名語法:
1 2 3 |
|
然後在匯入是,必須使用PIValue。
1 |
|
命名匯出某些內容之前必須先宣告它。
1 2 3 4 |
|
我們來看下面的validations.js 檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
在index.js中,我們可以使用如下函式:
1 2 3 4 5 6 7 8 |
|
JavaScript的預設匯出
如上所述,單個檔案中最多隻能有一個預設匯出。但是,你可以在一個檔案中使用多個命名匯出和一個預設匯出。
要宣告一個預設匯出,我們需要使用以下語法:
1 2 3 |
|
在匯入時就不需要再使用花括號了。
1 |
|
如下,我們有多個命名匯出和一個預設匯出:
1 2 3 4 5 6 |
|
此時我們使用import匯入時,只需要在大括號之前指定預設匯出的變數名。
1 2 |
|
使用 export default 匯出的內容,在匯入的時候,import後面的名稱可以是任意的。
1 2 3 4 5 6 |
|
另外, export default的變數名稱從Age到myAge之所以可行,是因為只能存在一個export default。因此你可以隨意命名。還需注意的是,關鍵字不能在宣告變數之前。
1 2 |
|
因此,我們需要在單獨的一行使用關鍵字。
1 2 3 |
|
不過以下形式是允許的:
1 2 3 4 5 |
|
並且需要在另一個檔案中使用它
1 2 3 |
|
還有,可以使用以下語法來匯入constants.js檔案中匯出的所有變數:
1 2 |
|
下面,我們將匯入所有我們constants.js儲存在constants變數中的命名和export default。因此,constants現在將成為物件。
1 2 3 4 5 6 |
|
在另一個檔案中,我們按一下方式使用。
1 2 3 4 5 6 7 |
|
也可以使用以下方式組合使用命名匯出和預設匯出:
1 2 3 4 5 6 7 8 9 10 |
|
總而言之:
ES6中,一個模組就是一個獨立的檔案,該檔案內部的所有變數,外部都無法獲取。如果想從外部讀取模組內的某個變數,必須使用export關鍵字匯出該變數,使用import關鍵字匯入該變數。
JavaScript中的預設引數
ES6增加了一個非常有用的特性,即在定義函式時提供預設引數。
假設我們有一個應用程式,一旦使用者登入系統,我們將向他們顯示一條歡迎訊息,如下所示:
1 2 3 4 |
|
但是,如果資料庫中沒有使用者名稱,那該怎麼辦呢?所以,我們首先需要檢查是否提供了firstName,然後再顯示相應的資訊。
在ES6之前,我們必須寫這樣的程式碼:
1 2 3 4 5 6 7 8 9 10 |
|
但現在使用ES6提供的預設引數,我們可以這樣寫:
1 2 3 4 5 6 |
|
函式的預設引數可以為任意值。
1 2 3 4 5 6 7 8 |
|
在上面的程式碼中,我們沒有提供函式的所有引數,實際程式碼等同於:
1 2 3 |
|
因此,如果傳遞的引數是undefined,則對應的引數將使用預設值。
我們還可以將物件或計算值指定為預設值,如下:
1 2 3 4 5 |
|
const display = (user = defaultUser, age = 60 / 2 ) => {
console.log(user, age);
};
display();
/* output
{
name: 'Jane',
location: 'NY',
job: 'Software Developer'
} 30
*/
ES5程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
在這段程式碼中,我們通過在getUsers函式中傳遞各種可選引數來進行API呼叫。在進行API呼叫之前,我們新增了各種if條件來檢查是否新增了引數,並基於此構造查詢字串,如下所示:
https://randomuser.me/api/? page=0&results=10&gender=male&nationality=us
使用ES6的預設引數則不必添這麼多if條件,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
這樣一來,程式碼得到了大量的簡化,即便我們不為getUsers函式提供任何引數時,它也能採用預設值。當然,我們也可以傳遞自己的引數:
1 |
|
它將覆蓋函式的預設引數。
null不等於未定義
注意: 定義預設引數時,null和undefined是不同的。
我們來看下面的程式碼:
1 2 3 4 5 6 7 8 |
|
當我們傳遞null作為引數時,它實際是給location引數賦一個空值,與undefined不一樣。所以它不會取預設值“NY”。
Array.prototype.includes
ES7增加了陣列的includes方法,用來判斷一個陣列是否包含一個指定的值,如果是返回 true,否則false。
1 2 3 4 |
|
陣列可以使用includes方法:
1 2 3 4 |
|
includes方法可以使程式碼簡短且易於理解,它也可用於比較不同的值。
1 2 3 4 5 6 7 8 9 10 |
|
因此,在檢查陣列中的值時,使用includes方法將會非常的方便。
結語
從ES6開始,JavaScript中發生許多變更。對於JavaScript,Angular,React或Vue開發人員都應該知道它們
瞭解這些變更可以使你成為更棒的開發者,甚至可以幫助您獲得更高的薪水。而且,如果你只是在學習React之類的庫以及Angular和Vue之類的框架,那麼您一定要掌握這些新特性。
相關文章
- 現代JavaScript:ES6+ 中的 Imports,Exports,Let,Const 和 PromiseJavaScriptImportExportPromise
- JavaScript中let、const、var 的區別JavaScript
- JavaScript 中的 Var,Let 和 Const 有什麼區別JavaScript
- JavaScript中的var、let 及 const 區別JavaScript
- JS中const、var 和let的區別JS
- ES6中let 和 const 的新特性
- JavaScript中的export、export default、exports和module.exports(export、export default、exports使用詳細)JavaScriptExport
- 理解let並 const在JavaScript ES6中(1)JavaScript
- 理解let並 const在JavaScript ES6中(2)JavaScript
- 理解let並 const在JavaScript ES6中(4)JavaScript
- [譯] 在JavaScript中何時使用var、let及constJavaScript
- ES6中let和var和const的區別
- var、let和const的區別
- var和let/const的區別
- When to use var vs let vs const in JavaScriptJavaScript
- var、let和const的知識點
- 【前端面試】(四)JavaScript var let const的區別前端面試JavaScript
- ES6 let和const命令
- var,let和const深入解析(一)
- 第二章 let和const的命令
- ES6中var,let,const的區別
- ES6中var/let/const的區別
- ES6語法——let和const
- let與const命令
- var、const、let 的區別
- JavaScript 高階—— ES6新增語法 const(let const var區別)JavaScript
- let const快取for迴圈的中間變數快取變數
- es6學習之let和const
- ES6入門——let和const命令
- 阮一峰的ES6---let和const命令
- 前端學習筆記 - var、let和const的用法前端筆記
- rspec中的let和let!區別
- let const var 區別
- var let const區別
- let與const區別
- let,const,var區別
- exports和module.exportsExport
- ES6系列——let和const深入理解