今天要談的內容也是JavaScript很核心的部分,即使學完了先前的章節,馬上去看別人寫的JavaScript程式碼還是會看不懂,主要是因為JS開發者會採用各種簡化和替代的寫法,我們一一討論。
首先我們要討論的是Anonymous(匿名) Function,在先前的章節中我們介紹過許多function的使用。那時候定義function一定會給名字,格式是這樣:
function 名稱() {}
但實際上在很多情況我們可以不給function指定名稱,我們稍微改寫一下的例子。
我們定義了eventAfterClicked()
再把它放進addEventListener()
的第二個參數,作為參考。但其實可以直接寫在參數裡面,這樣一來也不需要取名字,它就成為了anonymous function。
它的格式就變成了:
function () {}
anonymous function常常出現在以function作為參數的情境(Higher-Order Function)。但值得注意的是,因為沒有名字,在其他地方完全無法取得這個function。所以如果那個function是需要重複使用的,最好還是另外定義。
除了anonymous function,還有一種function的變體也很常出現,甚至幾乎是寫JS function的主流形式 — arrow function。
一樣用上面的例子,我們直接改寫成arrow function。
將function
這個關鍵字刪掉,並且加上=>
在小括號後面,我們就完成改寫了。
這就是arrow function的格式:
() => {}
主要就是讓定義function這件事變得更簡單、更容易。
arrow function還可以進一步簡化。
同樣舉例來說。
我們有一個numbers
array,用map()
這個method可以將它按照某種方式複製一份。map()
的參數需要一個function,這個function會對每個numbers
裡的元素做一次操作。每個元素是x
,function回傳x * 2
,於是最後我們可以得到一個數值被複製2倍的新array。
這是我們之前就做過的事,目前只是把function改成anonymous的形式。
現在我們繼續改成arrow function,並一步一步簡化。
如果都寫在一行,return
和{}
可以不寫(要一起不寫)。
還可以再簡化!
arrow function的參數如果只有一個,可以不用寫()
。
這跟一開始差別可大了。
這也就是很多人看到arrow function不一定能理解的原因之一,它簡單的太過分了。但從省略關鍵字開始,我們一步一步了解了它如何變成現在這樣。
this
arrow function裡還有一點很特別,我們先前提到的this
關鍵字在這裡運作有點不同。讓我們回到上個單元的例子。
我們可以把hungry()
改寫成arrow function:
要寫一個hungry()
arrow function,我們會用let
和=
再接arrow function。
從這裡可以看見,arrow function不會像傳統function一樣讓this
的值被覆寫掉(寫在hungry()
裡面和外面的this
值都一樣!),是比較簡單、比較直覺的。
arrow function除了比較簡潔以外,還有保留context的特色,讓它成為大多工程師的第一個選擇。
我們之前就已經看過幾次這種情境了。
這樣其實不太合理,因為程式碼是一行一行執行的,通常都要先定義才能使用。
可以這樣寫的原因就是function hoisting的機制,用function
關鍵字定義的會在背後被JS hoisting到最上方,優先處理。換句話說,在我們看不到的層面,其實定義sayHello()
那幾行會被放在實際執行它之前,這段才會正常運作。
但除此之外,我們也見到了其他定義function的方式。
但這兩種寫法都沒有function hoisting,所以會出錯。神奇吧…這就是JavaScript的運作方式。
其實總歸一句,就不要再定義之前先用function嘛,這樣還滿不符合邏輯的,不太建議。不過至少你現在知道為什麼那些情況在JS裡面也是可行了。
之前把字串連接起來我們都是用””
、’’
、+
這類的符號,寫起來又臭又長。
除了這種寫法以外,還有一種叫做template literal的方式。主要是用backtick(``)來取代''
或""
,backtick位在鍵盤上esc的下方或者在某些鍵盤中是esc本身透過組合鍵產生。
用template literal來改寫上述例子:
我們可以把``想成是有特殊功能的""
或''
,基本上引號能做到的它也能做到,但是多了一種能在文字中插入變數的能力。使用$
和{}
配合,就可以在string中放入變數或者計算式。用另外的角度說,在${}
內可以寫JavaScript。上面的例子中我們就將me
這個變數用template literal放入一串string之中。
如果裡面要放其他的JavaScript也都可以。
比起原本的方式更加簡潔好寫了,是很推薦的用法。
如同之前提到的,在JavaScript裡面有沒有加;
在結尾都是可行的,在某些程式語言裡並不是這樣。這個運作邏輯是,「如果正常的換行,JavaScript在執行的時候會自動加上分號。」,我們看以下的例子。
JavaScript會自動的在我們看不見的地方補上分號,給它正確的換行作為判斷標準是很重要的。我們其實也不太會把一堆東西寫在同一行啦,只是讓大家了解背後的機制。如果你換行換得太奇怪,大多編譯器的formatter都會幫你處理,也會跟你說哪裡有錯,不太需要擔心。至於要不要加分號,在JavaScript裡就變成了一種選項,有些人習慣、有些人不愛,大家也不要太糾結在這件小事上,讓formatter來為你處理就好。
==
和===
我們在條件判斷的單元裡看過==
,但在實際上我們可能更常看到用===
作為條件判斷。從先前的單元裡面我們看見其實JS好像不那麼要求變數的type(類別)
,這是因為JS內建一個自動的轉換機制,自動判斷類別。
舉例來說:
==
會允許自動型別轉換,string’3’
和number3
會因為這樣變得一樣,===
則不允許。所以在使用===
的情況下,兩者要type
和value
都一樣,才會回傳true
。這樣是比較嚴謹的。
目前看起來問題還不算太大,但還有很多例子這樣的操作顯得不太合理。
就以第一個為例,假設我是想要判斷使用者是不是沒輸入資料(情況應該是’’
空字串),但使用者輸入0
也被算進來,就很奇怪。下面兩個例子更是尤其,而且除此之外還有更多非常離奇、難判斷的例子。因此普遍的建議是嚴謹一點,使用===
來作判斷。
今天我們談了非常多在JavaScript裡面常見的寫法以及某些特殊的規則,再加上前面幾單元的內容,希望比之前更了解JS程式碼的運作方式。例如,常見array後出現一長串連續map()
、filter()
再加上anonymous arrow function,第一次看見還真的會被嚇到,今天開始你可以知道這是怎麼回事了。
明天,我們會討論JavaScript語法中備受關注的的內容,async和await語法。如同之前我們看到function hoisting的應用,JS程式碼不總是照著順序逐個運作的,有些情況下我們希望它不要這樣做。在最後這個單元中,我們將面對這個稍具挑戰的主題。
我是Erkin, 一個網站開發者。
有任何疑問或是想勘誤的話歡迎聯繫。