完成一个新鲜的需求:如何将一串 js 链式挪用存储在一个函数或对象中,以备将来挪用?

我置信读到本文题目的人基本上是懵 B 的,我着实想不出更好的表述要领。简单说,我想完成这么一个功用:

假定有一个对象 foobar,他的要领支撑链式挪用。比方如许:

var foobar = new Foobar();

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

注重 segmentfault 并不一定返回 this,然则要返回一个同范例对象,不然 foobar.segment(1).fault(2).segment(3).fault(4) 如许的代码就能够不合法。这是我迥殊增加的束缚,满足这一条下面的文章和才有意义

如今我想完成一个包装函数 makePolicy,完成如许的语法(假定 Foobar 一切要领都支撑链式挪用):

var policy = makePolicy(Foobar).segment(1).fault(2);
var foobar = new Foobar();

policy(foobar); // 等效于挪用 foobar.segment(1).fault(2)

这里比较难完成的,就是 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); // 等效于挪用 foobar.segment(1).fault(2)

之所以有如许的需求,重要是为了完美 js 参数搜检器(这篇文章)中的逻辑衔接的功用。为了轻易使用,我想写出如许的接口:

// 搜检 param 是不是在区间(1,3) 与 (2,4) 的交集内
check(param, 'param').and(check.policy.gt(1).lt(3), check.policy.gt(2).lt(4));

// 搜检 param 是不是在区间(1,2) 与 (3,4) 的并集内
check(param, 'param').or(check.policy.gt(1).lt(2), check.policy.gt(3).lt(4));

function myCheck(obj) {
    return obj.length > 4;
}

// 搜检 param 是不是是数组而且长度大于 4
check(param, 'param').and(check.policy.is('array'), myCheck);

// 搜检 param 是不是*不是*[1,3]之间的偶数(即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) 就是我想完成的语法功用。原本 check(a).gt(1).lt(3) 是马上实行的代码,经由过程 policy 的包装,var fn = check.policy.gt(1).lt(3) 成了一个函数,我能够把 fn 存储起来在恣意时候挪用,相当于实行 gt(1).lt(3) 搜检。

需求讲清楚了,剩下的就是开脑洞了。对比下面的代码梳理一下思绪:

var policy = makePolicy(Foobar).segment(1).fault(2);
var foobar = new Foobar();

policy(foobar); // 等效于挪用 foobar.segment(1).fault(2)

起首,我试验了一下,policy 的语法想象实际上很难完成,由于 js 中没有轻易的语法表达“函数类”、“函数实例”如许的观点,所以 policy 不合适设想为一个函数,让步一下,把 policy 设想为一个 包括 exec 要领的对象,挪用 policy.exec(...) 即可实行响应功用。

第二,将 policy 设想为一个 Policy 类的实例,由于 policy 能够会有很多要领,这些要领是在 makePolicy 函数中从输入类原型上依据名字一个一个扒下来的,比较合适放在 prototype 中。以及,依据输入类的差别,Policy 应当在 makePolicy 中动态天生,然后马上 new 一个实例返回,如许我们能够随时天生恣意类的 policy 包装。

综合以上思索,我们要完成的接口改成如许:

var policy = makePolicy(Foobar);
var functor = policy.segment(1).fault(2); // fn 存储了链式挪用的途径和参数
var foobar = new Foobar();

functor.exec(foobar); // 等效于挪用 foobar.segment(1).fault(2)

下面是简化的完成代码:

/**
 * 天生 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();
}

由上面的代码可知,当我们在链式挪用函数时,递次是从左到右。而 policy 在运行时,是先挪用最右侧的 policy 然后经由过程 prev_ 指针一起回溯到最左侧,然后再从左到右实行下来。

有了上面的完成,js 参数搜检器(这篇文章)的功用差不多就完整了,有兴致的同砚能够在这里看到详细完成。不过现在的完成依然有很多限定,在现在的基础上,我们实在能够完成越发通用,无所谓是不是是链式挪用的 policy 语法,等我做出来在写文章报告。

末了讨教一个题目:policy 这个名字是我瞎起的,如许的功用应当叫什么名字呢?roadmap?blueprint?想不出来。

    原文作者:Y3G
    原文地址: https://segmentfault.com/a/1190000006032391
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞