链式调用

jquery 的链式调用

相信大家对于链式调用不会感到陌生,我们在 jquery 经常使用:

$('.div').css('color', 'red').show();

想要实现链式调用,通常我们会在支持链式调用的函数中返回对象本身:

let car = {
    run(seconds) {
        console.log('begin run')
        for(let i=0;i<seconds;i++) {}
        return this;
    },
    stop() {
        console.log('stopped!');
    }
};

car.run(5).stop();
// => begin run
// => stopped

但是,这样做并不优雅,这需要我们手动地在函数中添加 return this 语句。更好的做法是我们创建一个通用函数,他能为指定的对象方法增加链式调用机制:

/**
 * 为指定的对象方法添加链式调用功能
 * @param  {Object} obj
 * @param  {Array} functions
 */
function chained(obj, functions) {
    functions.forEach((funcName) => {
        const func = obj[funcName];
        // 用支持链式调用的方法覆盖原有方法
        obj[funcName] = function () {
            func.apply(this, arguments);
            return this;
        }
    });
}

let car = {
    run(seconds) {
        console.log('begin run')
        for(let i=0;i<seconds;i++) {}
    },
    stop() {
        console.log('stopped!');
    }
};

chained(car, ['run']);
car.run(5).stop();

_.chain()

_.chain(obj):为 underscore 对象的方法增加链式调用能力。

下面这段代码将找出 stooges 中的最年轻的并且输出其信息:

const stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}];
const youngest = _.chain(stooges)
  .sortBy(stooge => stooge.age)
  .map(stooge => stooge.name + ' is ' + stooge.age)
  .first()
  .value();
// => "moe is 21"

_.chain 源码如下:

_.chain = function (obj) {
    // 获得一个经underscore包裹后的实例
    var instance = _(obj);
    // 标识当前实例支持链式调用
    instance._chain = true;
    return instance;
};

当我们期望对 obj 接下来的行为链化的话,会创建一个包裹了 obj 的 underscore 实例对象,并标识该实例需要进行链式调用,最后返回该实例以继续链式调用。

并且,underscore 还提供了一个帮助函数 chainResult,该函数将会判断方法调用结果,如果该方法的调用者被标识了需要链化,则链化当前的方法执行结果:

var chainResult = function (instance, obj) {
    return instance._chain ? _(obj).chain() : obj;
};

_.each(['concat', 'join', 'slice'], function (name) {
    var method = ArrayProto[name];
    _.prototype[name] = function () {
        return chainResult(this, method.apply(this._wrapped, arguments));
    };
});

当我们想要获得链式调用的结果时,可以看到,需要通过 _.prototype.value 方法获取,该方法返回了被包裹的对象:

_.prototype.value = function () {
    return this._wrapped;
};

results matching ""

    No results matching ""