旅程來到了第 10 天,這趟旅程真的有點硬啊...不過每天只要花一點點時間,就能讓逐漸讓自己變強,這樣的感覺是不是很棒呢?
今天的主題輕鬆一點,來看看 JavaScript ES6 中大家都會用的箭頭函式與一般函式的差異。
本系列文已經重新編校彙整編輯成冊,並正式出版囉!
《前端三十:從 HTML 到瀏覽器渲染的前端開發者必備心法》好評販售中!
喜歡我文章內容的讀者們,歡迎您 前往購買 支持!
在 ES6 版本之前的 JavaScript 是沒有箭頭函式可以用的,僅有最基本的一般函式。基本語法相信大家少說也寫過成千上萬次,對它應該都不太陌生,那麼這邊僅針對幾點可能容易被忽略的特性,做一些簡單的分享:
開發者可以透過 function
及 ()
關鍵字來定義、撰寫函式:
function fn() {
// something awesome
}
另一種常見的寫法,是宣告一個變數,等號右邊放上函式宣告:
var newFunc = function fn() {
// something awesome
}
兩種寫法在使用上唯一的差異,就是第二種寫法在宣告前不能使用。
快問快答小知識:
Q:請問第二種寫法中的 newFunc.name 是什麼?
A:是fn
,而不是newFunc
喔~
另外還有一種透過函數建構子的宣告方法:
var func = new Function('str', 'console.log(str)')
func('test')
但這樣子撰寫就無法利用 JavaScript 引擎會事先解析程式並準備 EC 的特性,造成效能上的冗余浪費,非常不推薦使用。
函式在 JavaScript 中,其實是一個可被呼叫(Callable)的物件,除了可執行、擁有例如 apply()
、bind()
、call()
之類的方法外,也擁有一些函式特有的屬性:
這兩者是 readonly 的屬性,在函式建立後即不能被修改。
另外有兩個已從標準廢棄,但主流瀏覽器仍支援的屬性:
由於已經是被廢棄的屬性,未來隨時可能會被瀏覽器放棄支援,所以開發上能不用就盡量不用吧。
另外,在函數執行的過程中,還有一個額外的 argument 物件可以使用,是一個傳入參數組成的類陣列(Array-like)物件
小提醒一下,被廢棄的是 Function.argument,而非在函式執行時直接呼叫的 argument 物件!
JavaScript 中還有個讓新手開發者難以捉摸的屬性 - this
,不過別擔心, 在預設情況下,函式中的 this
都是指向呼叫他的物件的。
例如以下範例:
function whatIsThis(){
console.log(this)
}
let obj = {
whatIsThis: whatIsThis
}
whatIsThis() // window
obj.whatIsThis() // obj
剛剛說了「預設情況」,那什麼時候是非預設情況呢?
稍有經驗的開發者應該想到了,我們可以透過 apply()
、bind()
、call()
等函式,改變函式的 this,有興趣深入理解的讀者們,可以參考 筆者以前寫過的相關文章,這邊就不贅述了。
雖然口頭上都稱呼為箭頭函式(Arrow Function),但實際上他是箭頭函式運算式(Arrow Function Expression)指的是類似這樣的語法:
const arrow = (param1, param2) => {
// do something awesome
}
由於中間的 =>
形似箭頭而得名;且撰寫起來快速直覺 ,看起來又很潮,深得開發者的喜愛。
除了前述的語法外,在特定條件下箭頭函式的語法可以進一步簡化:
// 基本用法
const arrow1 = (param1, param2) => { ... }
// 僅有一個參數時,可省略括號
const arrow2 = params => { ... }
// 單一運算後直接回傳時,可省略大括號
const arrow3 = params => params ** 2
另外,有一定熟悉度的開發者,可能會利用箭頭函式的特性,撰寫出如下的程式碼:
let fancy = x => y => z => x + y + z
遇到多層的箭頭函式,乍看之下可能會難以理解,但其實只要關注「箭頭」的位置,右到左的反向拆解,並把省略的部分加回去:
let fancy = (x) => {
return (y) => {
return (z) => {
return x + y + z
}
}
}
就不會那麼難懂了對吧?
藉由箭頭函式的各種省略,開發者可以用更短的語法寫出更精簡的程式 ,而且看起來很潮,是不是很不錯呢?
與前面說明的一般函式相同,可以取得 name、length 屬性,就不重複說明了。
箭頭函式的重點特色來了;箭頭函式中的 this
,會依據函式在哪裡建立而決定,而非與一般函式一樣,依照執行時被呼叫的地方決定。
一樣來看個範例:
var tmp = 'a'
var obj = {
tmp: 'b',
func: () => console.log(this.tmp)
}
console.log(tmp) // a
obj.func() // a
參照範例,由於 obj.func
是在全域環境中建立,this
就被綁訂到全域環境中;因此兩個執行結果印出來的結果都是全域變數 tmp
的值 a
另外,一般函式用來強制綁定 this
值的 apply()
、bind()
、call()
,在箭頭函式中沒有 bind()
,且 apply()
及 call()
傳入的 this
值會被忽略,各位讀者在使用時務必要特別注意喔!
今天仔細端詳了在程式開發過程中不斷頻繁使用的函式,並針對一般寫法及箭頭函式做說明和比較,希望有幫助讀者您更近一步的認識它們!
以上就是今天的箭頭函式,如果大家對文中內容有任何想法,都歡迎讀者您於文末留言回應。進行了三分之一的旅程也將繼續前進,明天也讓我們繼續一起逐步變強吧!
筆者
Gary
半路出家網站工程師;半生熟的前端加上一點點的後端。
喜歡音樂,喜歡學習、分享,也喜歡當個遊戲宅。相信一切安排都是最好的路。
var tmp = 'a'
var obj = {
tmp: 'b',
func: () => console.log(this.tmp)
}
console.log(tmp) // a
obj.func() // a
你好,這段代碼obj.func() //undefined
並不是a
請問何者是正確的?感謝
你好,我猜是因為你的JS環境是設定成StrictMode嚴格模式,嚴格模式 會防止this指標指向Global 區域,當夾帶this指標操作的函式在最外層被呼叫時,以往this會變成指向global。在StrictMode下,this會強制改為undefined。