5
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()が呼び出されるため)、2番目の呼び出しでfalseを返す必要があります。

より高度なバージョンでは、_hasChainedFunc()は、後で実際に呼び出される関数も返す場合があります。

4

9 に答える 9

6

技術的には、現在の呼び出しの後にチェーン化された別の呼び出しがあるかどうかを事前に知ることはできません。これは、呼び出される前に呼び出されるコードを認識していることを意味するため、明らかに意味がありません。プリコンパイラなしではこれを行うことはできません。これは、あなたが求めているものではないと思います。

逆に、現在の呼び出しのにチェーンされた以前の呼び出しがあったかどうかを確認することできます。これには、以前の呼び出しに関するオブジェクトの状態を保持し、新しい関数を呼び出すたびに更新する必要があるだけです。呼び出しのチェーンを 1 つだけ使用する場合は、オブジェクトを返す前にオブジェクトの状態を作成および変更することでこれを行うことができます。func1func2this

同じオブジェクトで複数のチェーンを呼び出したい場合、チェーンの終わりを検出する方法の問題に直面します。このためには、チェーンされた各関数が元の の周りにラッパーを返すようthisにする必要があります。これにより、以前の呼び出しに関する状態が保存されます。

ラッパー アプローチを使用する場合、はonをobj.func1().func2()呼び出しますが、から返されたラッパーで呼び出され、このラッパーは前の呼び出しを認識する可能性があります。後で呼び出すと、前の呼び出しを認識しているラッパーで呼び出されるのに対し、今は呼び出されます。func1objfunc2func1func1obj.func2().func1()func2objfunc1func2

于 2012-10-01T19:36:51.463 に答える
1

いいえ、できません。

意味的には次のものと同じです。

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

Obj.func1()呼び出されると、後続の結果が を呼び出すために使用されるかどうかを知る方法がありませんfunc2

あなたが達成できる最善の方法は、以前に呼び出されたfunc2かどうかを検出することですが、説明した方法で機能するには、将来を予測できる必要があります。func1func1

于 2012-10-01T19:27:03.403 に答える
0

できることは、チェーンの最初の要素用と残りの要素用の 2 つの別個のクラスを持つことです。次に、最初のクラスを変更して、現在のオブジェクトではなく、2 番目のクラスから同等のオブジェクトを返すようにするだけです。

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();
于 2012-10-01T19:43:51.810 に答える
0

いいえ。これはうまくいきません。func1() がある時点でこのオブジェクトに対して呼び出されたことはわかるかもしれませんが、それが呼び出された時期、つまりfunc2の直前はわかりません。

たとえば、これ:

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

呼び出し例と同等です。そして、func2 が将来呼び出されることを func1 が知る方法はありません。

これに似た問題をチェーン関数で解決しました(docs)。これにより、「先読み」してチェーンに何が来るかを確認する機能を備えた真の関数チェーンが可能になります。

于 2012-10-01T19:36:29.857 に答える
0

なぜこれをしたいのですか?

その質問はさておき、実際のオブジェクトを返すのではなく、そのクローンを作成し、それがオブジェクトの返されたバージョンであることを示す属性を追加することができます。それが私が考えることができる唯一の方法です。ただし、このオブジェクトの複雑さに応じて、複雑に聞こえます。

何かのようなもの:

func1 : function() {
  // some code
  if (this._hasChainedFunc()) {
     // block should be CALLED
  }
  return deepCloneWithFlag(this);
},
_hasChainedFunc : function() {
   return this.flag;
}
于 2012-10-01T19:31:11.960 に答える
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 に戻すことによって) オブジェクトの状態をリセットする必要があることを意味します。これについてどのように行っているかを再考する必要があるかもしれません。

于 2012-10-01T19:29:14.547 に答える
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/

于 2012-10-01T19:29:52.463 に答える
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
于 2013-02-08T19:53:06.397 に答える