我是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')
我发现我可以使用原型属性来增加可链接性,如此处所述How to make chainable function in JavaScript? 但同样的答案说它不应该在对象上完成,这将是我的情况......
最后但并非最不重要的是,另一种方法是JavaScript Object Method Chaining: useful? 坦率地说,我不明白......
有人可以清除我心中的所有迷雾吗?
<小时/> 修改 使用和混合来自@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() )
答案 0 :(得分: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();
不可链接。
答案 1 :(得分:1)
以下是一个关于如何使任何对象方法可动态链接的示例。
调用chainable(obj)
将在内部创建一个新对象,该对象公开与obj
相同的API,但是每个函数现在都将返回该新对象,而该对象又允许链接。如果要调用函数并获取该函数的原始结果,可以调用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
个参数。
<强> DEMO 强>
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使用不支持它的对象,这可能很有用。
E.g。
var o = {
fn1: function () { console.log('fn1'); },
fn2: function () { console.log('fn2'); }
};
//chainable(o).fn1().fn2(); //other implementation
chainable(o).chain('fn1').chain('fn2');
这是一个performance test,它表明您的对象可动态链接,对性能产生巨大的负面影响。出于这个原因,我不建议使用该实验方法。