一直以為有發過這篇,結果竟然沒有!
學習 JavaScript 這麼久了,筆記中當然不能少了 ES6 常用語法囉~
變數宣告
var
與 let
的區別
- 是否會提升
當我們分別用var
跟let
並在宣告變數之前調用變數時,var
會顯示undefined
,代表記憶體有預先準備空間;let
則會顯示not defined
,代表記憶體沒有預先準備空間。 - 作用域不同
var
是以 function 做分隔,let
是以 block ({}
) 做分隔。
const
代表常數,唯讀,不可再次賦值。但是如果用 const
宣告一個物件,可以在之後修改或新增該物件內部的特性,因為物件是傳址(參考)而不是傳值,所以可以這樣做。其他特色與 let
一樣。
迴圈內的 setTimeout()
假如我們希望用 setTimeout
配合迴圈輸出 1~10,而且每次輸出都延遲 10 毫秒:
1 | for( var i=0; i<10; i++){ |
此時迴圈的計數器 i
是用 var
來宣告,則 setTimeout
得到的數字不會是 1~10,而是得到最後的數字 10,為什麼會這樣呢?
因為 JS 非同步的特點,所以 for
迴圈並不會等到 setTimeout()
結束後才繼續,而是一口氣跑完 1~10;又因為 var
的作用域是以 function 做切分,setTimeout()
的 i
會從外層去取值,此時的 i
已經是跑完 for
迴圈的 10 了。
解決方法是改用 let
宣告計數器,這樣 setTimeout
得到的就會是當下迴圈跑的數字。
另一種解法:立即函式 (IIFE)
除了改用 let
宣告以外,也可以用立即函式包住 setTimeout
,並將迴圈的 i
作為參數傳入立即函式中,保留當下的 i
一筆筆輸出數字。
1 | // 立即函式語法 |
1 | // 用立即函式包住 setTimeout() |
展開符號 …
展開符號能夠把陣列與類陣列裡的內容給取出來。以下說明展開符號的幾個用途。
合併數個陣列
在一個新宣告的陣列中,把展開符號 ...
加在要合併的陣列前方,這種合併的方式與使用 concat()
的效果是一樣的。
1 | let groupA = ['小明', '杰倫', '阿姨']; |
複製陣列(淺複製)
陣列與物件一樣,都是傳址(傳參考),所以如果將 B 陣列指向 A陣列,A、B 陣列會被視為同一個實體。如此一來,當我們想要修改 B 陣列時,就會連 A 陣列的內容也修改到。這叫做深複製。
如果只想修改 B 陣列的話,就可以用展開符號來複製 A 陣列,再進行操作。只傳值的複製方式,就是淺複製。
1 | let groupA = ['小明', '杰倫', '阿姨']; |
類陣列
有些東西外觀很像陣列,也具有一些陣列的特性,但卻不是真正的陣列,稱為類陣列,例如用 querySelectorAll()
取出來的 NodeList
會以類陣列的形式呈現所有被選取的節點,但它卻不是真正的陣列。
在新的空陣列中,透過展開符號可以複製類陣列中的內容,藉此將類陣列轉為真正的陣列。
1 | let doms = document.querySelectorAll('li'); // doms 為類陣列 |
另一個類陣列的例子是函式內建的 arguments
物件,arguments
會包含所有傳入函式的參數。
1 | var originCash = 1000; |
其餘參數
如果不確定之後要傳入函式的參數數量,可以在函式的唯一一個或最後一個參數前面加上展開符號(該參數就會變成其餘參數),就能把多傳入的參數值以陣列的形式,容納在其餘參數中。
注意,函式裡只能有一個其餘參數,而且一定要放在最右邊。
1 | function moreMoney(...money) { |
解構賦值
解構賦值語法可以將陣列或物件中的資料取出成獨立變數。
基本上就是把等號右邊的值,套用到等號左邊。
陣列解構賦值
基本用法
在之前,我們如果要修改陣列內的元素,都只能用 =
一個一個直接賦值。
1 | let family = ['小明', '杰倫', '阿姨', '老媽', '老爸']; |
而現在可以用解構的方式,一次對陣列內所有元素賦值。
1 | let family = ['小明', '杰倫', '阿姨', '老媽', '老爸']; |
當輸入的變數少於所給的值
如果缺少的變數是陣列最後的值,那就會因為沒有被賦予變數而查不出來。
1 | let family = ['小明', '杰倫', '阿姨', '老媽', '老爸']; |
如果缺少的變數是在陣列中間的話,缺少的變數要留空,此時其他變數依然可以按照對應的陣列元素賦值。
1 | let family = ['小明', '杰倫', '阿姨', '老媽', '老爸']; |
當輸入的變數多於所給的值
如果變數的數量多於賦予的值時,多出來的那個變數會被賦予 undefined
的值。
1 | let family = ['小明', '杰倫', '阿姨', '老媽', '老爸']; |
變數交換
使用解構賦值可以即時交換兩個變數的值,不需要透過宣告第三個變數來達成。
1 | let fruit = 'banana'; |
把字串的字取出並個別宣告變數
1 | let str = '吃飽沒'; |
預設值
1 | let [g = 'Grete', s = 'Steffi'] = ['葛蕾特']; |
物件解構賦值
陣列的解構賦值強調的是順序,而物件的解構賦值強調的則是屬性名稱,屬性名稱必須相互對應才能夠取得到值。
在物件解構賦值中,冒號前是用來對應物件的屬性名稱,冒號後才是真正建立的變數名稱和被賦值的對象。
參照:[筆記] JavaScript ES6 中的物件解構賦值(object destructuring)
基本用法
從物件中取出一個特性的值,並賦予這個值一個新的變數名稱。
1 | let person = { |
person.city
的值依然是 'Taichung'
,而透過解構賦值另外宣告的變數 address
的值也是 'Taichung'
。
延伸問題
1 | let { name: germanName, fruits: [, apple] } = { name: 'Grete', fruits: ['香蕉', '蘋果', '芭樂'] } |
左邊 fruits
特性要解構賦值的對象是右邊 fruits
的第二個值,所以在 apple
前面用逗點空了一個位置。
預設值
1 | let { fruits: apple = '蘋果' } = {}; |
第一個範例中,左邊預設 apple
等於 ‘蘋果’,因為右邊沒有傳新的值,所以會保持 apple
為蘋果。
第二個範例中,右邊傳了新的值,所以 apple
的值就變成鳳梨了。
縮寫
物件縮寫
將一個字串與一個物件,在另一個新物件裡合併。
新物件裡的特性名稱如果跟來源變數一致時,就可以使用縮寫。
1 | const Frieza = '弗利沙' |
在 Vue CLI 裡也會時常應用縮寫,例如以下的情境:
1 | import Vue from 'vue' |
物件方法縮寫
原始寫法:
1 | const newTeam = { |
縮寫:
把 :
跟 function
去掉。
1 | const newTeam = { |
注意:物件方法縮寫與箭頭函式的結果是不一致的。
縮寫搭配展開與解構賦值
任務:將一個物件賦值到新的變數,並新增一個特性到新物件中,而且不能更改到原物件(=避免參考)。
1 | const GinyuTeam = { |
箭頭函式
基本寫法
傳統函式長這樣:
1 | var callSomeone = function (someone) { |
改寫成箭頭函式長這樣:
1 | var callSomeone = someone => someone + '吃飯了'; |
如何改寫
把參數往前提,把關鍵字 function
刪掉,改成箭頭。
只有一個參數時可以不用小括號包起來,如果沒帶入參數就還是需要小括號。
如果只有單行程式碼而且只是要回傳一個值的情況下,可以省略大括號及 return
。
箭頭函式沒有 arguments
物件,所以如果要傳入多個參數值時,可以在箭頭函式的小括號內使用其餘參數。
與傳統函式最不同的地方:this 綁定差異
- 傳統函式:
this
取決於函式呼叫的方式 - 箭頭函式:
this
取決於被定義時所在的物件,「箭頭函式沒有自己的this
」,因此它都是採用其同層級的this
來作用。
寫 Vue methods
時最好使用傳統函式搭配縮寫,因為使用箭頭函式的話,this
指向的可能不是 Vue 實例。
參照:[筆記] JavaScript ES6 中的箭頭函數(arrow function)及對 this 的影響
善用方式
在進入箭頭函式之前,先把要指向的物件(this
)用變數儲存起來。
1 | var antie = { |
字串模板
各位在用 innerHTML
組字串時會不會感到很痛苦呢?我承認我會,因為各種標籤名、文字、加號、單雙引號,全部亂糟糟地都寫在一起,真 D 會讓人眼花啊!
還好,在ES6有新的寫法,可以讓我們好過一點。
基本用法
假設我們要在一個 <ul><li>
裡放入圖片:
1 | // HTML |
1 | // JS |
接下來要進行渲染至網頁,傳統寫法是這樣:
1 | list.innerHTML = '<li><img src='+ imgURL +'></li>' |
現在比較好的寫法是:
1 | list.innetHTML = `<li><img src=" ${imgURL} "></li>` |
新寫法中這個長得像重音符號的東西叫做「反引號」,${}
裡面可放入 JS 程式碼跟變數,支援 ES6 寫法。
組字串不需要使用加號,而選取變數的方法則是把變數名稱包在大括號內,前面再加個 $
符號,這樣就可以了。
搭配陣列方法使用
假設我們要根據一個陣列裡的資料,一筆筆輸出為 <ul> <li>
列表:
1 | // 陣列 |
map()
會把陣列裡所有元素傳進 callback 函式內運算,並且把運算後的元素以陣列的形式回傳。join()
會把陣列裡所有元素以指定的字符連接在一起,這個例子是讓元素間不要有任何字符、逗號。
常用陣列方法
forEach()
與 map()
兩者很像,但 forEach()
不會回傳值,而 map()
會回傳一個新的陣列。map()
的 callback 函式裡需要使用 return
來回傳運算後的結果,且也需要一個變數來接收 map()
執行後的新陣列。
filter()
filter()
與 find()
:filter()
回傳的是一個新陣列且裡面包含所有符合條件的元素,而 find()
只會回傳第一個符合條件的元素值。因此,find()
較適合用於搜尋一個特定的值。
every()
所有元素都符合條件才會回傳 true
。
some()
部分元素有符合條件就會回傳 true
。
reduce()
用於累加或比較值的大小。
累加
reduce()
第一個參數是一個 callback 函式,第二個參數是累加的起始值。
callback 函式的參數中,第一個參數為「前一個元素的值」,如果沒有前一個元素,就使用 reduce()
的第二個參數。
比較值的大小
配合使用 Math.max()
。