JavaScript
中定義一個方法主要可以分成兩種形式:
- 函式宣告
- 函式表示式
函式宣告
宣告體是最普通的,與其他語言也相近的一種方式。
function func(a, b) {
return a + b
}
func(1, 2) // 3
複製程式碼
不過,畢竟JavaScript!它有一個特性:函式提升。
函式提升:把所有函式提升到當前作用域上,從而可以做到“未宣告先呼叫”。
(劃重點!等下要考!)
函式表示式
這可能是目前用的最多的宣告方式,因為可以搭配箭頭函式“假裝自己在用函數語言程式設計”。
const func = function(a, b) {
return a + b
}
// 箭頭函式版本
const funcA = (a, b) => a + b
func(1,2) // 3
複製程式碼
但受變數作用域的關係,所以const
和let
沒有變數提升的能力。
funcA(1) // ReferenceError: funcA is not defined
const funcA = a => a
複製程式碼
燃鵝,這才剛剛開始…
函式表示式:匿名 & 具名
匿名就是上面那種,而具名就是給函式本體再起一個名字。
const func = function funcName() {}
複製程式碼
這樣有什麼用?後面那個名字又不能用!答案還是有區別的。
首先有一個函式名推斷,例如上面這個函式,那麼func.name
會返回funcName
,如果匿名函式的話[fn].name
會返回``
(在ES5的情況下,ES6會被推斷為外面的函式名)。其次這個名字可以在函式內部使用,當然了指代的就是自己了。
const func = function funcName(a, b) {
return a < 0 ? b : funcName(a+1-b, a)
}
func(431, 151) // 281
funcName(431, 151) // ReferenceError: funcName is not defined
console.log(func.name) // funcName
typeof funcName === `function` // false
複製程式碼
所以這種方式最適合遞迴函式了。
函式表示式依然是個常/變數
關鍵詞已經決定了這個“量”會以什麼形式存在,比如var
和let
是變數,const
是常量,並且let
還有作用域範圍。
const funcA = () => console.log(`A`)
funcA() // A
funcA = () => console.log(`AA`) // TypeError: Assignment to constant variable.
var funcB = () => console.log(`B`)
funcB() // B
funcB = () => console.log(`BB`)
funcB() // BB
複製程式碼
題外話:那麼就有個老生常談的問題了,函式表示式按道理來講是“靈活的”,那麼
function funcB() {
console.log(`B`)
}
funcB()
function funcB() {
console.log(`BB`)
}
funcB()
複製程式碼
兩個funcB
的結果分別會是什麼?
箭頭函式
又到了大家最最喜歡的箭頭函式環節,現在還有誰是不願意寫箭頭函式的?
const func = a => b => a + b
func(1)(2) // 3
複製程式碼
不過,箭頭函式兩個特點:
- 不會創造上下文(自身無
this
) - 必然是個匿名函式
- 沒有
arguments
不是兩點嗎?怎麼變成三點了?此時你可能會回去檢查剛剛那句話,但是我現在悄悄告訴你,其實是三點。
關於箭頭函式自身無this
,有很多文章講了this
的指向相關,可以翻看那些文章得到答案。
計算屬性函式名
這個應該是在“物件”的環境中存在,畢竟物件可以指代很多種只要是物件的情況。
const object = {
[`a` + `b`](a, b) {
return a + b
}
}
object.ab(1, 2) // 3
複製程式碼
這就實現了“函式名可以暫時不知道是什麼”的情況,通過計算來得到這個函式。
Other
new Function
這是一個不知道哪裡可以用得上但是可以用的方式:通過物件建立
const func = new Function(`a`, `b`, `return a + b`)
func(1, 2) // 3
複製程式碼
函式引數初始值
可能會有引數要初始值的需求,但可能沒有
function func(a = 1, b = 2) {
return a + b
}
func() // 3
複製程式碼
可能我們更常用的還有這些
const funcA = (obj = {}) => obj
const funcB = (arr = []) => arr
複製程式碼
但JavaScript
畢竟是「函式是第一公民」的語言,有機會會寫到很多高階函式。所以
const func = (fn = () => `YDJFE`) => fn.call(null)
複製程式碼
憑什麼函式作為引數就不能有初始值呢?當然是可以的呀!
總結
我只是想用JavaScript寫一個方法…為什麼這麼複雜…
(關於JavaScript
定義方法,如果還有其他姿勢歡迎補充~)