我只是想用JavaScript寫一個方法...

YDJFE發表於2019-02-28

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
複製程式碼

但受變數作用域的關係,所以constlet沒有變數提升的能力。

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
複製程式碼

所以這種方式最適合遞迴函式了。

函式表示式依然是個常/變數

關鍵詞已經決定了這個“量”會以什麼形式存在,比如varlet是變數,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定義方法,如果還有其他姿勢歡迎補充~)

相關文章