Underscore 整體架構淺析

韓子遲發表於2016-11-02

前言

終於,樓主的「Underscore 原始碼解讀系列」underscore-analysis 即將進入尾聲,關注下 timeline 會發現樓主最近加快了解讀速度。十一月,多事之秋,最近好多事情搞的樓主心力憔悴,身心俱疲,也想盡快把這個系列完結掉,也好了卻一件心事。

本文預計是解讀系列的倒數第二篇,最後一篇那麼顯然就是大總結了。樓主的 Underscore 系列解讀完整版地址 https://github.com/hanzichi/underscore-analysis

常規呼叫

之前寫的文章,關注點大多在具體的方法,具體的知識細節,也有讀者留言建議樓主講講整體架構,這是必須會講的,只是樓主把它安排在了最後,也就是本文,因為樓主覺得不掌握整體架構對於具體方法的理解也是沒有大的問題的。

Underscore 大多數時候的呼叫形式為 _.funcName(xx, xx),這也是 文件中 的呼叫方式。

最簡單的實現方式,我們可以把 _ 看做一個簡單的物件:

在 JavaScript 中,一切皆物件,實際上,原始碼中的 _ 變數是一個方法:

為什麼會是方法?我們接下去看。

OOP

Underscore 支援 OOP 形式的呼叫:

這其實是非常經典的「無 new 構造」,_ 其實就是一個 建構函式_([1, 2, 3]) 的結果就是一個物件例項,該例項有個 _wrapped 屬性,屬性值是 [1, 2, 3]。例項要呼叫 each 方法,其本身沒有這個方法,那麼應該來自原型鏈,也就是說 _.prototype 上應該有這個方法,那麼,方法是如何掛載上去的呢?

方法掛載

現在我們已經明確以下兩點:

  1. _ 是一個函式(支援無 new 呼叫的建構函式)
  2. _ 的屬性有很多方法,比如 _.each_.template 等等

我們的目標是讓 _ 的構造例項也能呼叫這些方法。仔細想想,其實也不難,我們可以遍歷 _ 上的屬性,如果屬性值型別是函式,那麼就將函式掛到 _ 的原型鏈上去。

原始碼中用來完成這件事的是 _.mixin 方法:

_.mixin 方法可以向 Underscore 庫增加自己定義的方法:

同時,Underscore 也加入了一些 Array 原生的方法:

鏈式呼叫

Underscore 也支援鏈式呼叫:

乍一看似乎有 OOP 和非 OOP 兩種鏈式呼叫形式,其實只是一種,_.chain([1, 2, 3])_([1, 2, 3]).chain() 的結果是一樣的。如何實現的?我們深入 chain 方法看下。

我們看下 _.chain([1, 2, 3]) 的結果,將引數代入函式中,其實就是對引數進行無 new 構造,然後返回例項,只是例項多了個 _chain 屬性,其他的和直接 _([1, 2, 3]) 一模一樣。再來看 _([1, 2, 3]).chain()_([1, 2, 3]) 返回構造例項,該例項有 chain 方法,呼叫方法,為例項新增 _chain 屬性,返回該例項物件。所以,這兩者效果是一致的,結果都是轉為了 OOP 的形式。

說了這麼多,似乎還沒講到正題上,它是如何「鏈」下去的?我們以如下程式碼為例:

當呼叫 map 方法的時候,實際上可能會有返回值。我們看下 _.mixin 原始碼:

result 是一個重要的內部幫助函式(Helper function ):

如果需要鏈式操作(例項會有帶有 _chain 屬性),則對運算結果呼叫 chain 函式,使之可以繼續鏈式呼叫。

小結

Underscore 整體架構,或者說是基礎實現大概就是這個樣子,程式碼部分就講到這了,接下去系列解讀最後一篇,講講這段時間(幾乎也是歷時半年了)的一些心得體會吧,沒錢的就捧個人場吧!

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

Underscore 整體架構淺析

相關文章