2

我是 JS 的新手,但我已经对该主题进行了研究,但没有找到详尽的答案。

我正在为一个项目使用 Angular JS,并且我有一个公开一些功能的服务:

var app = angular.module('myApp', [])

app.service('mySrv', function() {

    this.myFoo = function() {
        var anObject = {}
        //some code on the object...
        return anObject
    }

    this.myGoo = function() { // function(object) maybe?
        //some code on an object again
        return aNewObject
    }
}

然后在我的控制器中,我想做类似 JQuery 的事情,将 myFoo 的输出链接为 myGoo 的输入

$scope.myObj = mySrv.myFoo(['some','params']).myGoo('another_one')

我发现我可以使用原型属性来添加可链接性,如此处所述如何在 JavaScript 中制作可链接功能? 但是同样的答案说它不应该在对象上完成,这将是我的情况......

最后但同样重要的是,还有其他方法JavaScript Object Method Chaining: 有用吗?
坦率地说,我不明白……

有人可以清除我脑海中的所有迷雾吗?


编辑: 使用和混合来自@plalx 和@Connor 的优秀示例,我已经设法让这个片段工作,并且如您所见,缺少@plalx 示例的“可链接部分”。

那部分到底是做什么的?

var o = {
    setTest: function (test) {
        this.test = test;
        return this
    },
    getTest: function () {
        this.test = this.test.toUpperCase()
        return this
    },
    splitMe: function() {
        return this.test.split('')
    }
};

console.log( o.setTest('hello').getTest().splitMe() )
4

2 回答 2

1

这是一个关于如何使任何对象方法动态链接的示例。

调用chainable(obj)将在内部创建一个新对象,该对象公开与 相同的 API obj,但是现在每个函数都将返回该新对象,这反过来又允许链接。如果要调用函数并获取该函数的原始结果,可以调用endChain().

下面的实现效率不是很高,因为它必须遍历obj. 更好的方法是通过从您希望可链接的函数返回当前实例 () 来使您的方法可链接。this

演示

var chainable = (function () {

    function wrapFn(fn, obj) {
        return function () {
            var result = this._result = fn.apply(obj, arguments);

            return this;
        };
    }

    function Chainable(obj) {
        var k, v;

        for (k in obj) {
            if (typeof (v = obj[k]) !== 'function') continue;

            this[k] = wrapFn(obj[k], obj);
        }
    }

    Chainable.prototype.endChain = function () {
        return this._result;
    };

    return function (obj) {
        return new Chainable(obj);
    };

})();

var o = {
    setTest: function (test) {
        this.test = test;
    },
    getTest: function () {
        return this.test;
    }
};

console.log(chainable(o).setTest('test').getTest().endChain());

这是一个不需要迭代对象成员的不同实现。然而,它在语法上不太吸引人,我不确定它是否更有效,因为它需要slice参数。

演示

var chainable = (function (slice) {
    var Chainable = {
        init: function (obj) {
            this._obj = obj;

            return this;
        },

        chain: function (fn) {
            var obj = this._obj;

            this._result = obj[fn].apply(obj, slice.call(arguments, 1));

            return this;
        },

        end: function () {
            return this._result;
        }
    };

    return function (obj) {
        return Object.create(Chainable).init(obj);
    };
})(Array.prototype.slice);

var o = {
    setTest: function (test) {
        this.test = test;
    },
    getTest: function () {
        return this.test;
    }
};

console.log(chainable(o).chain('setTest', 'test').chain('getTest').end());

编辑:

使用和混合来自@plalx 和@Connor 的优秀示例,我已经设法让这个片段正常工作,并且如您所见,它缺少@plalx 示例的“可链接部分”。

chainable如果您的代码已经以可以链接的方式编写(例如,已经this从某些函数返回),您不需要类似的东西。我应该说得更清楚。我只是编写了chainable实现作为链接如何工作的示例。

但是,chainable您可以使任何对象可链接,即使它们的函数都没有明确地返回this。如果您想对不通过其 API 支持的对象使用链接,这可能会很有用。

例如

var o = {
    fn1: function () { console.log('fn1'); },
    fn2: function () { console.log('fn2'); }
};

//chainable(o).fn1().fn2(); //other implementation

chainable(o).chain('fn1').chain('fn2');

这是一个性能测试,显示使您的对象可动态链接会对性能产生巨大的负面影响。出于这个原因,我不建议使用这种实验方法。

于 2013-10-21T23:17:18.887 回答
1

你将不得不return this;像这样使用。

app.service('mySrv', function() {

    this.myFoo = function() {
        var anObject = {}
        //some code on the object...
        return this;
    }

    this.myGoo = function() { // function(object) maybe?
        //some code on an object again
        return this;
    }
}

如果它是可链接的,则不应返回任何其他东西,因为无论如何您都无法使用它。就像 jQuery 中的所有东西一样,有些东西offset();是不可链接的。

于 2013-10-21T22:31:19.883 回答