Reflection and Extend
這堂課將來介紹一個在很多 Libaries 會使用到的觀念 - Extend,而 Extend 又因為 Reflection 而成立,讓我們來了解一下這兩個名詞吧。
首先,來了解一下 Reflection 這個名詞,Reflection 指的是物件可以取得並更改自己的屬性 properties
和方法 method
。
延續上次堂課的範例,我們建立兩個物件 person
和 john
,並將 john
的 prototype
指向 person
1 | var person = { |
for in 基本應用
接著透過 for...in
列出物件 person
中的所有 properties
與 method
,也就是每個 for
迴圈的變數 prop
,結果會發現連 prototype
的方法 getFullName
也被囊括進去了。
1 | for (var prop in john) { |
判斷屬性是否為繼承 hasOwnProperty
那麼如果我們只希望取得該物件本身的 properties
該怎麼辦呢 ?
這時候便可以透過 prototypal chain
概念取得 base object
的方法 hasOwnProperty
來判斷該 property
是否來自於物件本身,是的話回傳 true
,反之則回傳 false
,因此我們就可以透過這個方法來篩選了。
1 | for (var prop in john) { |
underscore.js extend()
接下來我們將透過 underscore.js 這個 libaries 的 source code 進一步了解 extend 的觀念。
讓我們來看一下透過 underscore.js 中的 extend()
可以做到什麼 ; 在載入 underscrore.js
的程式碼後,我們可透過下底線 _
來使用其中所有 API,在 extned()
這個 API 中,第一個參數是我們要擴充的物件,後續的參數則是擴充的來源,所以透過 _.extend(john, jane, jim)
便可讓 john
得到 jane
和 jim
的所有 properties。
1 | var john = { |
接下來讓我們到 underscore.js extend source code 中,依序解析它的程式碼來了解它是如何辦到的。
首先,我們可以看到 extend 這個 API 來自於 createAssigner
這個函式,透過回傳一個函式這裡便形成一個 closures,以下依序為各個名詞的含意:
obj
: 要擴充的物件john
keysFunc
: 取得物件中所有key
的方法length
: 傳入的物件數,如果只傳一個物件john
則代表不擴充length < 2
,因此直接回傳- 第 1 個
for
: 從jane
物件開始遍歷 keys
: 擴充來源物件jane
和jim
的所有key
l
: 擴充來源物件jane
和jim
的所有key
的數量- 第 2 個
for
: 將擴充來源物件所有屬性指派給要擴充的物件john
1 | // Extend a given object with all the properties in passed-in object(s). |
以上便是透過解析 underscore.js 來了解 extend 概念,讓我們透過原型鍊 prototypal chain 的方式就可以擴充物件的屬性 ; 其實多閱讀這些知名 Library 的 source code 可以增進我們的程式撰寫技巧,讓我們用更聰明、簡潔的方式達到一樣的目的。