最近一星期重新翻修 jquery-oo-strengther
檔案已經重新改名為 jquery-oo-root
並且併入 jquery-power-dev 專案 (取得很自嗨)
本次重新變更許多設計與功能,修正很多問題
雖然概念仍舊類似,但基本上已經不相容,前版本要捨棄囉

原先設計當中,real class經由 proxy class產生
並由 proxy class呼叫 real class的 constructor (使用者自訂)
傳入使用者丟進 proxy class constructor的參數初始化
原本應該一氣呵成的步驟,卻不得不拆成兩步
這一直讓人覺得很不滿意

如果可以 real class之 constructor呼叫
應包含於 real class的 function內容中
然而最大的問題在於 proxy class執行 new指令時
沒辦法像一般 function呼叫一般將 arguments利用 apply函式傳入
一年前開發時,並未找到解決辦法
這個問題直到今天自我實驗的發現中才得到解決

關鍵在於 bind與 apply函式的應用
其實原本並沒有想到可以拿來解決這問題,完完全全是湊巧想到
在此之前必須先解釋 call、apply與 bind這三項屬於 Function.prototype的功能

  • call:call 函式讓未被綁定於物件中之函式
    在呼叫時能夠享有使用 this 與特定物件之特性,call函式之介面為
        call( bind, [ arg1 [ , arg2 [ , arg3 ... ] ] ] )
    舉例若有一函式 F 為 function(){ this........ }
    若 F 存在於某個物件 O中,使用 O.F() 呼叫時 this會被代入 O
    則直接呼叫 F() 時,使用 this並無特別意義,this會被代入 window變數
    此時若使用 F.call( O, arg1, arg2, ... )
    F中的 this便會被代入 O值,而 arg1, arg2...則會傳入 F參數列中
    若 O為 undefined、null等非物件參數,則與直接呼叫時無異
  • apply:apply運作原理與 call類似,apply函式之介面為
        apply( bind, array-like-object )
    然而一般而言我們並不會每次皆將參數以手寫方式代入
    特別是在可變長數之參數列中,開發者並沒辦法確切掌握參數數量
    此時可使用 apply函式將參數以陣列形式傳入
    參數僅需有陣列形式即可,並不一定要是 Array
    例如 function呼叫中,arguments變數就是一個有陣列形式的物件
    例如上例之 F,使用 F.apply( O, [ arg1, arg2, arg3 ..... ] )
    則 F之 this會代入 O,而陣列當中的 arg1, arg2, arg3會帶入 F之參數列中
  • bind:產生一個與特定物件綁定之函式複製品,介面
        bind( bind-object, [ arg1 [ , arg2 [ , arg3 .... ] ] ] )
    以上例 F為例若使用 F.bind( O, arg1, arg2, arg3 )
    即會產生一份 F的複製品 Fc,使用 Fc == F指令會發現得到 false值
    Fc當中 this便與 O完全綁定,而 arg1, arg2, arg3則為作為 Fc之預設參數
         例如使用 F() 呼叫,this便已是 O 值,並且已經包含三項參數
         若使用 F( a1, a2, a3 ),此時傳入之參數便會成為第四、第五與第六項
    即使使用 X.Fc() 之方式呼叫,this仍然會是 O不會變更
    除非 O 傳入 undefined或 null等非物件值,this才會代入 X

要解決 constructor無法使用 apply的問題
便需要再另行搭配 bind解決
今日查詢後已得知此項已是 ECMAScript'5的標準
大家可以放心在任何較新版瀏覽器使用
我們先從一個比較簡單的範例觀看

若執行 new F() 指令需要自動傳入參數
可使用 Fi = new ( F.bind(null, arg1, arg2, arg3) )() 執行
由於 F.bind產生的新函式,已經自動代入 3項參數
Fi 可以不必再自行傳入參數即可自動獲得資料
然而這種寫法事實上與自行傳入參數也沒差多少

我們需要的是更進階的用法,利用 apply將不固定數量之參數自動代入
指令為 Fi = new ( F.bind.apply( F, [ null, arg1, arg2, arg3 ] ) )
哇!看起來超複雜耶......。沒關係我們一步一步看
首先是 apply部分,請注意由於是 bind的 apply
因此會執行 bind函式的內容
由於是使用 F.bind的關係,故 bind.apply的參數 1最好代入 F
故 bind.apply部分會展開為 bind( null, arg1, arg2, arg3 )
因為是 F 作為 constructor用
故 F 當中的 this不當被任何值綁住,傳入 null 即可
範例中直接撰寫參數列表,當然也可以代入如 arguments這類物件
故 F.bind.apply 產生的 Fc 便已經含有傳入之不固定長度之參數啦

上述中,腦袋比較銳利的人可能會發現一個問題
F 與 Fc 是不同的函式,那 Fi = new F() 與 Fci = new Fc() 豈不是沒有關聯的物件?
這點可以完全放心,Fi instanceof Fc 將會求得 true值
Fci instanceof F 也會求得 true值
甚至檢查 Fci.constructor == Fi.constructor 仍舊會是 true值
因此 class 與 class instance的關係仍會維持喔

文章標籤
創作者介紹
創作者 wylokgo101 的頭像
wylokgo101

豆棚瓜架雨如絲 - WYLOKGO101

wylokgo101 發表在 痞客邦 留言(0) 人氣()