箭頭函式是什麼?
箭頭函式沒有this
什麼情況下該使用箭頭函式
在es6大行其道的今天,不應用點es6特性似乎有些政治不正確。最近剛好有個node的專案,最低要支援到nodejs 4.0,在node.green看了下es6的支援度,我想使用的特性基本都有支援,遂決定在新專案中採用es6來寫。
當然第一件事情就是毫不留情地消滅var,專案中能用const的地方不用let,能用let的地方不用var。
第二件事情就是使用勞動人民喜聞樂見的箭頭函式替代function。當我心滿意足地看到滿屏的=>
時,現實給了我一記響亮的耳光——改過之後的程式錯誤百出!
所以,當我們使用箭頭函式時,一定要搞清楚箭頭函式是什麼回事,適用於什麼場景。本文就針對以上問題來討論下箭頭函式。
箭頭函式的語法我就不講了,相信大家都見識過。跟我一樣,大家喜歡箭頭函式90%的原因是它好看。除了好看,它是不是與function等價呢?肯定不等價,因為tc39不可能僅因為好看而引入乙個語法糖(class除外)。
箭頭函式的淵源可以追溯到上古時期乙個叫lambda演算的東西。lambda演算是數學家提出來的,有些數學家跟我們程式設計師一樣也很懶,數學定理那麼多,今天要證三角定律,明天要證勾股定律,累不累!那能不能將所有的證明問題用乙個統一的體系進行形式化描述,然後由機器來完成自動推導呢?lambda演算就是幹這個的,圖靈也搞了一套體系叫圖靈機,兩者是等價的。
關於lambda演算說了這麼多,好像跟今天要講的箭頭函式沒什麼關係?其實是有關係的,lambda演算深刻影響了箭頭函式的設計。數學家們喜歡用純函式式程式語言,純函式的特點是沒有***,給予特定的輸入,總是產生確定的輸出,甚至有些情況下通過輸出能夠反推輸入。要實現純函式,必須使函式的執行過程不依賴於任何外部狀態,整個函式就像乙個數學公式,給定一套輸入引數,不管是在地球上還是火星上執行都是同乙個結果。
箭頭函式要實現類似純函式的效果,必須剔除外部狀態。所以當你定義乙個箭頭函式,在普通函式裡常見的this
、arguments
、caller
是統統沒有的。
箭頭函式沒有this
,那下面的**明顯可以取到this
啊:
1234567
8
function foo()以上箭頭函式中的foo() // 1
this
其實是父級作用域中的this
,即函式foo
的this
。箭頭函式引用了父級的變數,構成了乙個閉包。以上**等價於:
1234567
8910
function foo()箭頭函式不僅沒有foo() // 1
this
,常用的arguments
也沒有。如果你能獲取到arguments
,那它一定是來自父作用域的。
12345
function foo()上例中如果箭頭函式有foo(1, 2)(3, 4) // 1
arguments
,就應該輸出的是3而不是1。
乙個經常犯的錯誤是使用箭頭函式定義物件的方法,如:
123456
let a =以上**中,箭頭函式中的a.bar() //undefined
this
並不是指向a
這個物件。物件a
並不能構成乙個作用域,所以再往上到達全域性作用域,this
就指向全域性作用域。如果我們使用普通函式的定義方法,輸出結果就符合預期,這是因為a.bar()
函式執行時作用域繫結到了a
物件。
123456
let a =另乙個錯誤是在原型上使用箭頭函式,如:}a.bar() // 1
1234567
8
function a()同樣,箭頭函式中的a.prototype.bar = () => console.log(this.foo)
let a = new a()
a.bar() //undefined
this
不是指向a
,而是根據變數查詢規則回溯到了全域性作用域。同樣,使用普通函式就不存在問題。
通過以上說明,我們可以看出,箭頭函式除了傳入的引數之外,真的是什麼都沒有!如果你在箭頭函式引用了this
、arguments
或者引數之外的變數,那它們一定不是箭頭函式本身包含的,而是從父級作用域繼承的。
到這裡,我們可以發現箭頭函式並不是萬金油,稍不留神就會踩坑。
至於什麼情況該使用箭頭函式,《you don』t know about js》給出了乙個決策圖:
以上決策圖看起來有點複雜,我認為有三點比較重要:
箭頭函式適合於無複雜邏輯或者無***的純函式場景下,例如用在map
、reduce
、filter
的**函式定義中;
不要在最外層定義箭頭函式,因為在函式內部操作this
會很容易汙染全域性作用域。最起碼在箭頭函式外部包一層普通函式,將this
控制在可見的範圍內;
如開頭所述,箭頭函式最吸引人的地方是簡潔。在有多層函式巢狀的情況下,箭頭函式的簡潔性並沒有很大的提公升,反而影響了函式的作用範圍的識別度,這種情況不建議使用箭頭函式。
請不要濫用異常
exception php的異常機制的功能非常強大,並且是可以跨作用域的傳遞豐富的資訊,但它強大的功能很容易讓我們濫用它。比如在使用者檢查登入時,如果密碼不正確,你可能會在模型中丟擲乙個異常,在控制器處理它。對於程式設計師,這樣做會很舒服,因為你不再費心思考慮心如何構建返回值和制定返回規範,也不必關...
不要濫用網路資源
網路資源很豐富,地球人都知道。但是,請不要濫用網路資源。如今,很多人遇到乙個技術問題,首先想到的是去 google 一下,看看有沒有現成的 solution 這樣做的後果是,大家的 solution 都一樣,缺乏創新。我覺得,當你遇到問題時,得先自己想一想,搞出乙個自己的 solution 這個so...
Linq TO SQL 雖好,但不要濫用
看看下面的例子。我們的場景是,需要對客戶表按照國家進行分組,然後列印出來每個國家的客戶數目。下面的語法看起來很優雅 using system using system.linq 客戶總數 item.key,item.count foreach var i in item 但是,注意觀察一下,每迴圈乙...