2012-10-01 63 views
3
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第二次調用。如何檢測JavaScript中的鏈接函數調用?

在更高級的版本中,_hasChainedFunc()也可能返回實際上後來調用的函數。

回答

4

從技術上講,你永遠無法提前知道是否有其他呼叫後鏈接當前呼叫 - 這顯然是沒有意義的,因爲這意味着你是知道的一些代碼,這就是所謂的在此之前,是會被調用。沒有預編譯器就無法做到這一點,我想這不是你想要的。

相反,可以檢查是否有一直在上次通話當前呼叫之前鏈接。這隻需要您在對象中保留一些關於先前調用的狀態,並在您調用一個新的函數時更新它。如果您只使用一個呼叫鏈,您可以通過func1func2在返回對象之前更改this對象上的某些狀態來完成此操作。

如果你想在同一個對象上調用多個鏈,你就會面臨如何檢測鏈的結束的問題。爲此,您需要使每個鏈接函數返回一個包裝圍繞原始this,這將存儲關於以前的調用狀態。

如果您使用的包裝方式,obj.func1().func2()呼籲func1obj,但func2叫上一個包裝從func1返回,此包裝可以知道以前func1通話。如果你再打obj.func2().func1()然後func2現在叫上objfunc1叫上知道前面func2調用的包裝等

1

不,這是不可能的。

這是語義相同於:

var tmp = Obj.func1(); 
tmp.func2(); 

Obj.func1()被調用時,有沒有辦法爲它知道以後的結果是否會被用來調用func2

您可以實現的最好方法是用func2來檢測以前是否調用func1,但如果按照您所描述的方式運行,則需要func1才能夠預測未來。

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)。你可能想重新思考你如何去做這件事。

+0

不解決問題,你正在查找鏈(=向後看),但我想看看鏈條。 – Scholle

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 

http://jsfiddle.net/2VThj/1/

+0

與「rfw」的解決方案相同,您正在查找鏈條(=向後看),但我想要看鏈條。我想知道在我處理func1()時func2()是否會被調用。當「called2」被打印時,func1()已經返回。 – Scholle

+0

我不確定這是可能的。JavaScript執行'Obj.func1()'沒有任何知識後會發生什麼。 –

0

你爲什麼要這麼做?

除了這個問題之外,你可以,而不是返回實際的對象,做一個克隆它,並添加一個屬性來告訴你它是對象的返回版本。這是我能想到的唯一方法。聽起來很複雜,但取決於這個物體的複雜程度。

喜歡的東西:

func1 : function() { 
    // some code 
    if (this._hasChainedFunc()) { 
    // block should be CALLED 
    } 
    return deepCloneWithFlag(this); 
}, 
_hasChainedFunc : function() { 
    return this.flag; 
} 
0

都能跟得上。這是行不通的。你可以可能告訴FUNC1()不得不在某些時候被調用這個對象上,但你不能告訴WHEN它被稱爲,即前FUNC2

例如這一權利:

obj.func1(); 
obj.func2(); 

相當於您的示例調用。 func1不可能知道將來會調用func2。

我解決了類似於這個的問題chain functionsdocs)這允許真正的函數鏈接能夠「預見」以查看鏈中將要發生的事情。

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(); 
0

Althought知道函數將陸續函數調用是在Javascript中是不可能的,這裏是chainify對象的解決方案:

(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 
0

(注:這個答案最初發布的朔勒作爲問題的一部分,我將它從問題中提取到實際的答案中,因爲它應該放在第一位,這不是我的解決方案,所以我已將其標記爲Community Wiki。)

Scholle最終創建了一個圖書館,做他想做的事。
這是available on GitHub,有些文檔是here

總之:取一個任意JavaScript函數和 「chainify」 吧:

var Model = function() {}; 

Model.prototype.func1 = function() { 
    console.log('func1 has ' + this.c_getPredecessors().length + ' preceding functions'); 
    return this.c_delay().c_chain(function() { 
    console.log('func1 has ' + this.c_getSuccessors().length + ' succeeding functions');  
    console.log('func1 processing...'); 
    this.c_next(); 
    }); 
}; 

Model.prototype.func2 = function() { 
    console.log('func2 has ' + this.c_getPredecessors().length + ' preceding functions'); 
    return this.c_delay().c_chain(function() { 
    console.log('func2 has ' + this.c_getSuccessors().length + ' succeeding functions');  
    console.log('func2 processing...'); 
    this.c_next(); 
    }); 
}; 

Chainify並創建實例, 和調用一些功能:

chainify(Model); 

var Obj = new Model(); 
Obj.func1().func2(); 

控制檯輸出:

func1 has 0 preceding functions 
func2 has 1 preceding functions 
func1 has 1 succeeding functions 
func1 processing... 
func2 has 0 succeeding functions 
func2 processing... 

當然,這是一個簡單的例子。它僅證明每個 函數現在都能夠訪問有關在當前函數調用之前和之後發生的事情的信息。