成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

實(shí)現(xiàn)一個(gè)奇怪的需求:如何將一串 js 鏈?zhǔn)秸{(diào)用存儲(chǔ)在一個(gè)函數(shù)或?qū)ο笾?,以備未來調(diào)用?

jerry / 2154人閱讀

摘要:簡單說,我想實(shí)現(xiàn)這么一個(gè)功能假設(shè)有一個(gè)對象,他的方法支持鏈?zhǔn)秸{(diào)用。本來是立即執(zhí)行的代碼,通過的包裝,成了一個(gè)函數(shù),我可以把存儲(chǔ)起來在任意時(shí)刻調(diào)用,相當(dāng)于執(zhí)行檢查。

我相信讀到本文標(biāo)題的人基本上是懵 B 的,我實(shí)在想不出更好的表述方法。簡單說,我想實(shí)現(xiàn)這么一個(gè)功能:

假設(shè)有一個(gè)對象 foobar,他的方法支持鏈?zhǔn)秸{(diào)用。比如這樣:

var foobar = new Foobar();

foobar.segment(1).fault(2);

注意 segmentfault 并不一定返回 this,但是要返回一個(gè)同類型對象,否則 foobar.segment(1).fault(2).segment(3).fault(4) 這樣的代碼就可能不合法。這是我特別添加的約束,滿足這一條下面的文章和才有意義。

現(xiàn)在我想實(shí)現(xiàn)一個(gè)包裝函數(shù) makePolicy,實(shí)現(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)

這里比較難實(shí)現(xiàn)的,就是 makePolicy(Foobar).segment(1).fault(2)這句代碼。如果沒有這個(gè)需求,那直接這樣寫好了:

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) 就是我想實(shí)現(xiàn)的語法功能。本來 check(a).gt(1).lt(3) 是立即執(zhí)行的代碼,通過 policy 的包裝,var fn = check.policy.gt(1).lt(3) 成了一個(gè)函數(shù),我可以把 fn 存儲(chǔ)起來在任意時(shí)刻調(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)

首先,我實(shí)驗(yàn)了一下,policy 的語法設(shè)想實(shí)際上很難實(shí)現(xiàn),因?yàn)?js 中沒有方便的語法表達(dá)“函數(shù)類”、“函數(shù)實(shí)例”這樣的概念,所以 policy 不適合設(shè)計(jì)為一個(gè)函數(shù),妥協(xié)一下,把 policy 設(shè)計(jì)為一個(gè) 包含 exec 方法的對象,調(diào)用 policy.exec(...) 即可執(zhí)行相應(yīng)功能。

第二,將 policy 設(shè)計(jì)為一個(gè) Policy 類的實(shí)例,因?yàn)?policy 可能會(huì)有很多方法,這些方法是在 makePolicy 函數(shù)中從輸入類原型上按照名字一個(gè)一個(gè)扒下來的,比較適合放在 prototype 中。以及,根據(jù)輸入類的不同,Policy 應(yīng)該在 makePolicy 中動(dòng)態(tài)生成,然后立即 new 一個(gè)實(shí)例返回,這樣我們可以隨時(shí)生成任意類的 policy 包裝。

綜合以上思考,我們要實(shí)現(xiàn)的接口改為這樣:

var policy = makePolicy(Foobar);
var functor = policy.segment(1).fault(2); // fn 存儲(chǔ)了鏈?zhǔn)秸{(diào)用的路徑和參數(shù)
var foobar = new Foobar();

functor.exec(foobar); // 等效于調(diào)用 foobar.segment(1).fault(2)

下面是簡化的實(shí)現(xiàn)代碼:

/**
 * 生成 policy
 * @param proto 要生成 policy 的類原型
 * @return 生成的 policy 實(shí)例
 */
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ù)時(shí),順序是從左到右。而 policy 在運(yùn)行時(shí),是先調(diào)用最右邊的 policy 然后通過 prev_ 指針一路回溯到最左邊,然后再從左到右執(zhí)行下來。

有了上面的實(shí)現(xiàn),js 參數(shù)檢查器(這篇文章)的功能差不多就完整了,有興趣的同學(xué)可以在這里看到具體實(shí)現(xiàn)。不過目前的實(shí)現(xiàn)仍然有許多限制,在目前的基礎(chǔ)上,我們其實(shí)可以實(shí)現(xiàn)更加通用,無所謂是不是鏈?zhǔn)秸{(diào)用的 policy 語法,等我做出來在寫文章匯報(bào)。

最后請教一個(gè)問題:policy 這個(gè)名字是我瞎起的,這樣的功能應(yīng)該叫什么名字呢?roadmap?blueprint?想不出來。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87805.html

相關(guān)文章

  • JavaScript 工作原理之四-事件循環(huán)及異步編程出現(xiàn)和 5 種更好 async/await

    摘要:函數(shù)會(huì)在之后的某個(gè)時(shí)刻觸發(fā)事件定時(shí)器。事件循環(huán)中的這樣一次遍歷被稱為一個(gè)。執(zhí)行完畢并出棧。當(dāng)定時(shí)器過期,宿主環(huán)境會(huì)把回調(diào)函數(shù)添加至事件循環(huán)隊(duì)列中,然后,在未來的某個(gè)取出并執(zhí)行該事件。 原文請查閱這里,略有改動(dòng)。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第四章。 現(xiàn)在,我們將會(huì)通過回顧單線程環(huán)境下編程的弊端及如何克服這些困難以創(chuàng)建令人驚嘆...

    maochunguang 評論0 收藏0
  • JavaScript 未來:它還少些什么?

    摘要:例如通過哈希表映射需要一個(gè)操作來檢查值是否相等,另一個(gè)操作用于創(chuàng)建哈希碼。如果使用哈希碼,則對象應(yīng)該是不可變的。模式匹配提案目前處于第階段。在本文,我們研究其中的智能管道另一個(gè)提議被稱為。更強(qiáng)大,更重量級(jí),并附帶自己的數(shù)據(jù)結(jié)構(gòu)。 翻譯:瘋狂的技術(shù)宅原文:http://2ality.com/2019/01/fut... 本文首發(fā)微信公眾號(hào):jingchengyideng歡迎關(guān)注,每天...

    layman 評論0 收藏0
  • javascript 回調(diào)函數(shù) 整理

    摘要:回調(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng)。若是使用回調(diào)函數(shù)進(jìn)行處理,代碼就可以繼續(xù)進(jìn)行其他任務(wù),而無需空等。參考理解回調(diào)函數(shù)理解與使用中的回調(diào)函數(shù)這篇相當(dāng)不錯(cuò)回調(diào)函數(shù) 為什么寫回調(diào)函數(shù) 對于javascript中回調(diào)函數(shù) 一直處于理解,但是應(yīng)用不好的階段,總是在別人家的代碼中看到很巧妙的回調(diào),那時(shí)候會(huì)有wow c...

    xiaowugui666 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<