11

まず、最も重要なこととして、メソッド チェーンの終了呼び出しを検出しようとしています。また、メソッド チェーン内のメソッド呼び出し内にあるオブジェクト チェーンの "in" または "down" の数を検出する方法を考案したいと考えています。

たとえば、私が書いているプラ​​グインでは:

var result = $("#someDiv").myPlugin.foo().bar()._foo()._bar();

メソッドが現在 .bar() で実行されているとします。チェーンの 2 つのメソッドであることを知りたいと思います。

この情報を何らかの方法で抽象化する必要がある理由は、チェーンの最後のメソッドに到達したときに、プラグイン オブジェクトの代わりに結果を返すことができるため、その時点でチェーンを壊して、 「結果」変数。

4

5 に答える 5

5

これがあなたのプロジェクトから引き出された例です:

var strLenA = parseInt( P.strlen('some string').data );
var strLenB = parseInt( P.strlen('another string').data );
var totalStrLen = strLenA + strLenB;
console.log(strLenA, strLenB, totalStrLen);

これから、なぜ私たちの答えが本当に適切ではないのか、そしてなぜあなたがを取り除きたいのかがわかります.data。とにかく、幸いなことに、あなた.dataは常に文字列を返します。したがって、神秘的な.toStringオーバーライドを使用して、メソッドが親メソッドのコピーを返すようにすることができますが、文字列のように扱うこともできます。

次に例を示します:[フィドル付き]

var stringMagic = function() {
    var chain = "",
        self = this;
    self.toString = function () { return chain; }; // Where the real magic happens.
    self.add = function(str) {
        chain += str + " ";
        return self;
    };
};


var magi = new stringMagic();
alert(magi.add("hello").add("world")); // Alerts, "hello world"
magi.add("and").add("thanks").add("for").add("all").add("the").add("fish");
alert(magi); // Alerts, "hello world and thanks for all the fish"

あなたの場合、おそらくあなたがしなければならないのは、に変更.dataP.toStringそれを関数でラップすることだけです。

将来、数値やブール値などの他のデータ型のサポートを追加するときvalueOfに、と同じように使用できますtoStringtoString実際、戻り値が文字列ではない場合も、その数値を文字列として扱っている場合(inconsole.logや。など)も引き続き含める必要があります$.fn.text。上記の例を次に示しますが、数字を使用しています:http: //jsfiddle.net/emqVe/1/

于 2013-01-02T15:54:42.753 に答える
2

完全を期すために。さらに別の方法として、チェーンの進行に合わせて更新されるオブジェクトを渡す方法があります。これにより、いつでも結果値にアクセスできます (チェーンの最後に追加する必要はありません)。

次のような構文の代わりに:

var result = chainableFunction.doThis().doThat().result;

次に、次のようになります。

chainableFunction.update(variableToUpdate).doThis().doThat();
var result = variableToUpdate.result;

ロジックは、他の人が提案したソリューションとほとんど同じです。どちらを使用するかは、おそらくユースケースによって異なります。チェーンを .result で終了する必要がある場合に考えられる問題は、この方法を使用することを妨げるものは何もないということです:

var chainedUp = chainableFunction.doThis().doThat();
doSomething(chainedUp.result);
... 
chainedUp.doOneMoreThing()
... 
doSomething(chainedUp.result);  // oups, .result changed!

variableToUpdate オプションを使用すると、結果の値は将来の関数呼び出しの影響を受けません。繰り返しますが、これはある状況では望ましいことですが、別の状況では望ましいことではありません。

以下の完全な例

#!/usr/bin/env node

var ChainUp = {};
(function(Class) {

  // Pure functions have no access to state and no side effects
  var Pure = {};
  Pure.isFunction = function(fn) {
     return fn && {}.toString.call(fn) === '[object Function]';
  };

  Class.instance = function() {
    var instance = {};
    var result;
    var updateRef;

    function callBack(fn) {
      // returning a clone, not a reference.
      if(updateRef) { updateRef.r = (result || []).slice(0); } 
      if(Pure.isFunction(fn)) { fn(result); }
    }

    instance.update = function(obj) {
      updateRef = obj;
      return instance;
    };

    instance.one = function(cb) {
        result = (result || []); result.push("one");
        callBack(cb);
        return instance;
      };
      instance.two = function(cb) {
        result = (result || []); result.push("two");
        callBack(cb);
        return instance;
      };
      instance.three = function(cb) {
        result = (result || []); result.push("three");
        callBack(cb);
        return instance;
      };
      instance.result = function() {
        return result;
      };
    return instance;
  };

}(ChainUp));


var result1 = {};
var chain = ChainUp.instance().update(result1);
var one = chain.one(console.log); // [ 'one' ]
console.log(one.result());        // [ 'one' ]
console.log(result1.r);           // [ 'one' ]

var oneTwo = chain.two(); 
console.log(oneTwo.result());  // [ 'one', 'two' ]
console.log(result1.r);        // [ 'one', 'two' ]

var result2 = {};
var oneTwoThree = chain.update(result2).three();
console.log(oneTwoThree.result()); // [ 'one', 'two', 'three' ]
console.log(result2.r);            // [ 'one', 'two', 'three' ]

console.log(result1.r);             // [ 'one', 'two' ]

ノート。Class および instance キーワードは、おそらくなじみのないものです。これは、プロトタイプからインスタンスを構築するためにプロトタイプの継承の代わりにクロージャーを使用するときに使用する規則です。instance を self に置き換えることができます (instance = {} の代わりに self = this)。

于 2013-09-26T12:30:05.313 に答える
1

メソッドが結果を返した後、外部の結果で何が起こるかをメソッドで見つける(合法的または簡単または適切な)方法はありません。「チェーン エンド マーク」方式を使用する必要があります。

もう一度考えてみてください。オブジェクトに最後に適用されたメソッドを探しているのでしょうか、それとももっと明示的なものを検出したいのでしょうか? 決定にメソッドを適用する可能性を失う可能性があります (偽のばかげたメソッド名を使用):

obj.turnLeft().pushUp().makeBig().makeSilent;
if (colorSupport) {
  obj.paintRed();
} else {
  obj.paintStripes();
}
obj.makeShine().lastMethodCallSoObjectIsNowInFinalState();
于 2013-01-02T14:29:40.860 に答える
1

戻り値を決定するときに、呼び出しがチェーンの最後のインスタンスであるかどうかを判断することはできません。その理由は次のとおりです。

var result = $("#someDiv").myPlugin.foo().bar()._foo()._bar();

foo呼び出されたときに返されmyPluginます。呼び出されたときに返されます。呼び出されたときに返されます。barmyPlugin_foomyPlugin_bar

したがって、実際に_fooは、その値 ( ) を返すときは、そのmyPlugin値が使用される前です。霊能者でない限り_foo、次に何が起こるかわかりません。

コメントで指摘されているように、最善の策は、のような「終了」メソッドを用意することresults()です。

別の提案は、 をmyPlugin使用して値を設定するために呼び出される にハンドラーを渡すことsetTimeout(..., 0)です。myPluginその foo、bar、_foo、および _bar にすべて値を設定します。と呼びましょうreturnValue。メソッドを唯一のパラメーターとして受け入れるように myPlugin を変更します。と呼びましょうhandler。このメソッドの最初の引数には値が含まれます。myPlugin の内部で、 の前に、次のようreturnにします。

window.setTimeout(function () {
    handler(returnValue);
}, 0);

setTimeout の関数パラメータは実行が終了するまで呼び出されないため、最後に設定された値が含まれますreturnValue。つまり、チェーン内の最後の呼び出しによって設定された値です。開発者は自分のメソッドのどれが最後に呼び出されるかを心配する必要がないため、これがあなたが達成しようとしていることに最も近いオプションだと思います。

于 2013-01-02T14:30:22.020 に答える