var Obj = {
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be NOT called
}
return this;
},
_hasChainedFunc : function() {
// code which detects if there is a chained function???
}
}
Obj.func1().func2();
是否有可能实现函数 _hasChainedFunc()?此函数应在第一次调用时返回 true (因为之后调用func2()),第二次调用时返回 false 。
在更高级的版本中, _hasChainedFunc()也可能会返回之后实际调用的函数。
答案 0 :(得分:4)
从技术上讲,你可以事先知道在当前通话之后是否还有另一个被锁定的电话 - 这显然没有意义,因为它意味着你知道一些以前会被调用的代码它被称为。如果没有预编译器,你就无法做到这一点,我想这不是你想要的。
相反, 可以检查在当前通话之前是否存在先前已锁定的通话。这只需要您在对象中保留一些关于先前调用的状态,并在您调用其上的新函数时更新它。如果您只使用一个调用链,则可以通过func1
和func2
更改this
对象上的某个状态来执行此操作。
如果要在同一对象上调用多个链,则会遇到如何检测链末端的问题。为此,您需要使每个链接函数返回原始this
周围的包装器,这将存储有关先前调用的状态。
如果您使用包装器方法,obj.func1().func2()
会在func1
上调用obj
,但会在func2
返回的包装器上调用func1
,此包装器可以请注意之前的func1
电话。如果您稍后致电obj.func2().func1()
,则会在func2
上调用obj
,而在知道之前的func1
调用等的包装器上调用func2
。
答案 1 :(得分:1)
不,这是不可能的。
它在语义上与:
相同var tmp = Obj.func1();
tmp.func2();
调用Obj.func1()
时,无法知道后续结果是否会用于调用func2
。
您可以实现的最佳效果是func2
检测先前是否func1
被调用,但是为了使其按照您所描述的方式工作,需要func1
能够预测未来。
答案 2 :(得分:0)
您可以做的是添加一个成员属性,指示它是否是对该对象进行的第一次调用:
var Obj = {
_first : true,
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be NOT called
}
return this;
},
_hasChainedFunc : function() {
var isFirst = this._first;
this._first = false;
return isFirst;
}
}
Obj.func1().func2();
但是,这意味着您必须在每次调用之前重置对象的状态(通过将this._first
设置回true)。你可能想重新考虑一下这个问题。
答案 3 :(得分:0)
这是我怎么做的:
var Obj = {
first:0, //<--- will store whether it's the first call
func1 : function() {
// some code
if (this._hasChainedFunc()) {
console.log("called1");
}
return this;
},
func2 : function() {
// some code
if (this._hasChainedFunc()) {
console.log("called2");
}
return this;
},
_hasChainedFunc : function() {
return (this.first++ > 0);
}
}
Obj.func1().func2();
这似乎有效:
called2
答案 4 :(得分:0)
你为什么要这样做?
除了这个问题之外,您可以,而不是返回实际对象,复制它,并添加一个属性来告诉您它是对象的返回版本。这是我能想到的唯一方法。听起来很复杂,取决于这个对象的复杂程度。
类似的东西:
func1 : function() {
// some code
if (this._hasChainedFunc()) {
// block should be CALLED
}
return deepCloneWithFlag(this);
},
_hasChainedFunc : function() {
return this.flag;
}
答案 5 :(得分:0)
不。这不行。你可能可能告诉func1()在某个时刻被调用过这个对象,但你无法告诉 WHEN 它被调用,即在func2之前
例如:
obj.func1();
obj.func2();
等同于您的示例调用。并且func1无法知道将来会调用func2。
我使用chain functions(docs)解决了与此类似的问题。这允许真正的函数链接,具有“预见”的能力,以查看链中的内容。
答案 6 :(得分:0)
你可以做的是有两个独立的类,一个用于链中的第一个元素,另一个用于其余元素。然后你要做的就是改变第一个类,从第二个类而不是当前对象返回一个等价对象。
var Class1 = function(state){
return {
func1 : function() {
// some code
// block should be CALLED
return Class2(state)
},
func2 : function() {
// some code
// block should be NOT called
return Class2(state)
}
};
}
var Class2 = function(state){
return {
func1 : function() {
// some code
return this;
},
func2 : function() {
// some code
return this;
}
};
}
Class1(initial_state).func1().func2();
答案 7 :(得分:0)
虽然知道在Javascript中无法使用另一个函数后将调用函数,但这是一个链接对象的解决方案:
(function(window, undefined)
{
var chainify = function(prop)
{
return new chainify.init(prop);
};
/**
*
* @param prop :
* Properties to apply to the object
* @returns {chainify.init}
*/
chainify.init = function(prop)
{
for ( var key in prop)
this[key] = prop[key];
};
chainify.init.prototype = {
_attributes : {},
_chain_in_progress : false,
_chain_level : 1,
_chain_function : '',
/**
* Returns the chained object
*
* @param name -
* name of the previous function
* @this chainify.init
* @returns {chainify.init}
*/
_chain : function(name)
{
var tmp = chainify(this);
tmp._chain_in_progress = true;
tmp._chain_function = name || '';
_chain_level++;
return tmp;
},
get : function(key)
{
return this._attributes[key];
},
set : function(key, value)
{
this._attributes[key] = value;
return this;
},
attr : function(prop)
{
for ( var key in prop)
this._attributes[key] = prop[key];
return this;
},
};
// Make global
window.chainify = chainify;
})(window);
var myObject = window.chainify({
// f1() function is using _chain()
f1 : function(s)
{
// Do something
this.set('s1', s);
if (this._chain_in_progress) alert('f1 after ' + this._chain_function);
// return the chain by calling this._chain()
return this._chain('f1');
},
// f2() function is using _chain()
f2 : function(s)
{
this.set('s2', s);
if (this._chain_in_progress) alert('f2 after ' + this._chain_function);
return this._chain('f1');
},
// that() function is not using _chain(), but we return this so the chaining
// is not broken
that : function(s)
{
// Do something
return this;
}
});
// Check if the f1 function is working
myObject.f1('a'); // Set s1 to "a"
alert(myObject.get('s1')); // should be "a"
// check if the f2 chaining is working
myObject.f1('b').f1('c'); // f1 after f1
alert(myObject.get('s1')); // should be "c" -> changed on last f1 function
// Check if the f2 function is working
myObject.f2('a');
alert(myObject.get('s2')); // should be "a"
// check if the f2 and f1 chaining is working
myObject.f2('b').f1('c').f1('d').f2('e'); // f1 after f2, f1 after f1 ...
alert(myObject.get('s1')); // should be "d" -> changed on last f1 function
alert(myObject.get('s2')); // should be "e" -> changed last f2 function
// check the chain with that() -
myObject.that('b').f1('a').f1('z'); // f1 chained after f1
alert(myObject.get('s1')); // should be "z" -> changed on last f1 function