摘要:簡單說,我想實現(xiàn)這么一個功能假設(shè)有一個對象,他的方法支持鏈?zhǔn)秸{(diào)用。本來是立即執(zhí)行的代碼,通過的包裝,成了一個函數(shù),我可以把存儲起來在任意時刻調(diào)用,相當(dāng)于執(zhí)行檢查。
我相信讀到本文標(biāo)題的人基本上是懵 B 的,我實在想不出更好的表述方法。簡單說,我想實現(xiàn)這么一個功能:
假設(shè)有一個對象 foobar,他的方法支持鏈?zhǔn)秸{(diào)用。比如這樣:
var foobar = new Foobar(); foobar.segment(1).fault(2);
注意 segment 和 fault 并不一定返回 this,但是要返回一個同類型對象,否則 foobar.segment(1).fault(2).segment(3).fault(4) 這樣的代碼就可能不合法。這是我特別添加的約束,滿足這一條下面的文章和才有意義。
現(xiàn)在我想實現(xiàn)一個包裝函數(shù) makePolicy,實現(xiàn)這樣的語法(假設(shè) Foobar 所有方法都支持鏈?zhǔn)秸{(diào)用):
var policy = makePolicy(Foobar).segment(1).fault(2); var foobar = new Foobar(); policy(foobar); // 等效于調(diào)用 foobar.segment(1).fault(2)
這里比較難實現(xiàn)的,就是 makePolicy(Foobar).segment(1).fault(2)這句代碼。如果沒有這個需求,那直接這樣寫好了:
var policy = function (that) { var newThat = Foobar.prototype.segment.call(that, 1); Foobar.prototype.fault.call(newThat , 2); }; var foobar = new Foobar(); policy(foobar); // 等效于調(diào)用 foobar.segment(1).fault(2)
之所以有這樣的需求,主要是為了完善 js 參數(shù)檢查器(這篇文章)中的邏輯連接的功能。為了方便使用,我想寫出這樣的接口:
// 檢查 param 是否在區(qū)間(1,3) 與 (2,4) 的交集內(nèi) check(param, "param").and(check.policy.gt(1).lt(3), check.policy.gt(2).lt(4)); // 檢查 param 是否在區(qū)間(1,2) 與 (3,4) 的并集內(nèi) check(param, "param").or(check.policy.gt(1).lt(2), check.policy.gt(3).lt(4)); function myCheck(obj) { return obj.length > 4; } // 檢查 param 是否是數(shù)組并且長度大于 4 check(param, "param").and(check.policy.is("array"), myCheck); // 檢查 param 是否*不是*[1,3]之間的偶數(shù)(即2) check(param, "param").not.and( check.policy.is("number").not.lt(1).not.gt(3), function (obj) { return obj % 2 === 0; });
上面的代碼中,check.policy.gt(1).lt(3) 就是我想實現(xiàn)的語法功能。本來 check(a).gt(1).lt(3) 是立即執(zhí)行的代碼,通過 policy 的包裝,var fn = check.policy.gt(1).lt(3) 成了一個函數(shù),我可以把 fn 存儲起來在任意時刻調(diào)用,相當(dāng)于執(zhí)行 gt(1).lt(3) 檢查。
需求講清楚了,剩下的就是開腦洞了。對照下面的代碼梳理一下思路:
var policy = makePolicy(Foobar).segment(1).fault(2); var foobar = new Foobar(); policy(foobar); // 等效于調(diào)用 foobar.segment(1).fault(2)
首先,我實驗了一下,policy 的語法設(shè)想實際上很難實現(xiàn),因為 js 中沒有方便的語法表達(dá)“函數(shù)類”、“函數(shù)實例”這樣的概念,所以 policy 不適合設(shè)計為一個函數(shù),妥協(xié)一下,把 policy 設(shè)計為一個 包含 exec 方法的對象,調(diào)用 policy.exec(...) 即可執(zhí)行相應(yīng)功能。
第二,將 policy 設(shè)計為一個 Policy 類的實例,因為 policy 可能會有很多方法,這些方法是在 makePolicy 函數(shù)中從輸入類原型上按照名字一個一個扒下來的,比較適合放在 prototype 中。以及,根據(jù)輸入類的不同,Policy 應(yīng)該在 makePolicy 中動態(tài)生成,然后立即 new 一個實例返回,這樣我們可以隨時生成任意類的 policy 包裝。
綜合以上思考,我們要實現(xiàn)的接口改為這樣:
var policy = makePolicy(Foobar); var functor = policy.segment(1).fault(2); // fn 存儲了鏈?zhǔn)秸{(diào)用的路徑和參數(shù) var foobar = new Foobar(); functor.exec(foobar); // 等效于調(diào)用 foobar.segment(1).fault(2)
下面是簡化的實現(xiàn)代碼:
/** * 生成 policy * @param proto 要生成 policy 的類原型 * @return 生成的 policy 實例 */ function makePolicy(proto) { function Policy(fn, prev) { this.fn_ = fn; this.prev_ = prev; } Policy.prototype.exec = function (that) { var myThat = that; var prev = this.prev_; var fn = this.fn_; if (prev) { myThat = prev.exec(that); } return fn(myThat); }; for (var key in proto) { if (proto.hasOwnProperty(key)) { Policy.prototype[key] = (function (fnName) { return function () { var self = this; var args = Array.prototype.slice.call(arguments, 0); return new Policy(function (that) { return proto[fnName].apply(that, args); }, self); } })(key); } } return new Policy(); }
由上面的代碼可知,當(dāng)我們在鏈?zhǔn)秸{(diào)用函數(shù)時,順序是從左到右。而 policy 在運行時,是先調(diào)用最右邊的 policy 然后通過 prev_ 指針一路回溯到最左邊,然后再從左到右執(zhí)行下來。
有了上面的實現(xiàn),js 參數(shù)檢查器(這篇文章)的功能差不多就完整了,有興趣的同學(xué)可以在這里看到具體實現(xiàn)。不過目前的實現(xiàn)仍然有許多限制,在目前的基礎(chǔ)上,我們其實可以實現(xiàn)更加通用,無所謂是不是鏈?zhǔn)秸{(diào)用的 policy 語法,等我做出來在寫文章匯報。
最后請教一個問題:policy 這個名字是我瞎起的,這樣的功能應(yīng)該叫什么名字呢?roadmap?blueprint?想不出來。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/87805.html
摘要:函數(shù)會在之后的某個時刻觸發(fā)事件定時器。事件循環(huán)中的這樣一次遍歷被稱為一個。執(zhí)行完畢并出棧。當(dāng)定時器過期,宿主環(huán)境會把回調(diào)函數(shù)添加至事件循環(huán)隊列中,然后,在未來的某個取出并執(zhí)行該事件。 原文請查閱這里,略有改動。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第四章。 現(xiàn)在,我們將會通過回顧單線程環(huán)境下編程的弊端及如何克服這些困難以創(chuàng)建令人驚嘆...
摘要:例如通過哈希表映射需要一個操作來檢查值是否相等,另一個操作用于創(chuàng)建哈希碼。如果使用哈希碼,則對象應(yīng)該是不可變的。模式匹配提案目前處于第階段。在本文,我們研究其中的智能管道另一個提議被稱為。更強(qiáng)大,更重量級,并附帶自己的數(shù)據(jù)結(jié)構(gòu)。 翻譯:瘋狂的技術(shù)宅原文:http://2ality.com/2019/01/fut... 本文首發(fā)微信公眾號:jingchengyideng歡迎關(guān)注,每天...
摘要:回調(diào)函數(shù)不是由該函數(shù)的實現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時由另外的一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng)。若是使用回調(diào)函數(shù)進(jìn)行處理,代碼就可以繼續(xù)進(jìn)行其他任務(wù),而無需空等。參考理解回調(diào)函數(shù)理解與使用中的回調(diào)函數(shù)這篇相當(dāng)不錯回調(diào)函數(shù) 為什么寫回調(diào)函數(shù) 對于javascript中回調(diào)函數(shù) 一直處于理解,但是應(yīng)用不好的階段,總是在別人家的代碼中看到很巧妙的回調(diào),那時候會有wow c...
閱讀 3115·2021-11-19 09:40
閱讀 1574·2021-11-15 11:39
閱讀 688·2021-10-08 10:05
閱讀 2284·2021-09-03 10:29
閱讀 3416·2021-08-12 13:22
閱讀 2185·2019-08-30 15:54
閱讀 3724·2019-08-30 14:03
閱讀 2664·2019-08-30 13:45