web-dev-qa-db-ja.com

オーバーロードされたメソッドの一般的なチェーン手法

JavaScriptの一般的な操作は、元のメソッドを呼び出したまま、オブジェクトメソッドを新しいメソッドに置き換えることです。これは多くの場合、次のように行われます。

var originalMethod = obj.method;
obj.method = function(arg) {
    // call original method
    originalMethod.call(this, arg);
    // do my stuff new stuff
}

連鎖部分を処理する特定のオブジェクトメソッドのユーティリティ関数を作成して、ユーザーがそれについて心配する必要がないようにしたいと思います。 1つのオプションは、上記の設計を使用することです。この設計では、追加された各関数が、前の関数を呼び出す新しい関数にラップされます。もう1つのオプションは、関数の配列を作成し、オブジェクトメソッドが配列を反復処理して、各関数を順番に呼び出すようにすることです。

function addXyzMethod1(fn) {
    if (obj.method) {
        var previousMethod = obj.method;
        obj.method = function(value) {
            value = previousMethod.call(this, value);
            return fn.call(this, value);
        };
    } else {
        obj.method = fn;
    }
}

function addXyzMethod2(fn) {
    if (obj._methodList) {
        obj._methodList.Push(fn);
    } else if (obj.method) {
        obj._methodList = [obj.method, fn];
        obj.method = function(value) {
            for (var i = 0, n = obj._methodList.length; i < n; i++) {
                value = obj._methodList[i].call(this, value);
            }
            return value;
        };
    } else {
        obj.method = fn;
    }
}

現時点では、それぞれのトレードオフはほぼ均等であると感じているため、どちらの方法を使用するかを決めることはできません。したがって、ここでの私の質問は、これらの方法のどちらが優れているか(より自然であるか、受け入れられているか、またはより速いか)、またはこれらの両方を改善する別の方法がありますか?

2
Michael Best

この質問は非常に似ているか、少なくともここで同様の質問になります: https://stackoverflow.com/questions/660337

そこで好意的な答えを読んで、私はあなたがあなたがすることを知っているaddXyzMethod1ifに固執することをお勧めしますスタックオーバーフローの危険に直面するほど頻繁に関数を上書きする必要はありません。

別の解決策が必要な場合(私の意見では望ましいでしょう)、何をしようとしているのかを正確に理解することが役立ちます。私は長い間このテクニックを必要としませんでした、そして私の経験から、これはほとんどの場合悪い習慣です。この状況を回避するのに役立つデザインパターンがあります。例えば。合成を使用します。関数のコレクションを表すオブジェクト(関数の単純な配列にすることができます)を用意し、コンストラクターを介してそのオブジェクトをオブジェクトに挿入し、メンバーとして格納します。次に、最初に置き換えたいメソッドで使用します。挿入したコレクションでも、関数を追加したり削除したりできます。これは、addXyzMethod2に似ていますが、グローバルutil関数がなく、オブジェクトの元のメソッドを上書きする必要もありません。

1

あなたがやろうとしているのは、JavaScriptバージョンのコールスーパーです。これは Martin Fowlerによってコードの臭いとして説明されています です。

代わりに、どちらかをお勧めします

  1. 継承するのではなく、「スーパー」オブジェクトを含みます。
  2. 以下のようなテンプレートメソッドを使用します

    templateMethod = function () {
         baseMethod();
         if (overrideMethod) {
              overrideMethod();
         }
    };
    

他のオブジェクトはtemplateMethodを呼び出します。 overrideMethodは、子オブジェクトがコードを持つ場所です。

1
Aaron Kurtzhals