2017-05-20 19 views
1

実際のコードはより大きいので、投稿しません。問題無限ループで配列関数を再利用する方法

class A { 
    process(source) { 
     // I perform several operations with array helper functions here: 
     const filtered = source.filter(item => item); 
     const condition = filtered.some(item => item); 

     if (condition) { 
      const mapped = source.map(item => /* Mapping operations... */); 
      const sorted = mapped.sort((a, b) => { /* Some sort conditions... */ }); 
      return sorted; 
     } else { 
      const mapped2 = filtered.map(item => /* A different mapping operation... */); 
      return mapped2; 
     } 
    } 
} 

const a = new A(); 

while (true) { 
    const source = getSourceFromSomewhere(); // Array (40 - 50 items aprox) 
    const b = a.process(source); 
    // ... 
} 

:これはかなりこのようになります基本的には、パフォーマンス。 "ループ内で関数を作成しない"。

すべての反復で、一連の匿名関数が作成されています。

私のソリューション:

class A { 
    // Predefine it: 
    sort() { /* Sort logic */ } 
    map() { /* Map logic */ } 
    map2() { /* Map logic */ } 
    filter() { /* Filter logic */ } 
    some() { /* Condition */ } 

    process(source) { 
     const filtered = source.filter(this.filter); // Note: Scope of 'this' is changed. 
     const condition = filtered.some(this.some); 

     if (condition) { 
      const mapped = source.map(this.map); 
      const sorted = mapped.sort(this.sort); 
      return sorted; 
     } else { 
      const mapped2 = filtered.map(this.map2); 
      return mapped2; 
     } 
    } 
} 

もう一つの問題:この機能の一部は、オブジェクト自体のプロパティにアクセスする必要がありますが、thisの範囲が変更されました。

匿名機能を作成する代わりに.bind(this)を呼び出すのは価値がありますか?またはほぼ同じですか?

私の場合はどうしますか?

ありがとうございます。あなたはとにかくやりたいこと

class Test { 
    fn = (t) => this[t] 
} 

は基本的に同じ行うことができ、クラス内に結合機能を初期化するために

答えて

1

+0

これはどのように動作するはずです。 'fn'はどこで呼び出されますか? 'fn( 'foo')は' this.foo'とどう違うのですか?クラスの 'this'の代わりに、' fn'の中の 'this'が周囲の' this'ではありませんか? –

1

問題:基本的にはパフォーマンスです。 "ループ内で関数を作成しない"。

あなたの前提が正しくありません。

JavaScriptエンジンは高度に最適化されています。ループごとに、または関数が呼び出されるたびに、コールバックが呼び出されるたびにソーステキストを文字単位で読みにくくなります。スキャン、解析、および事前コンパイルを行います。最悪の場合、item => itemのような関数は、関数の呼び出しごとに1回しか作成されません。おそらく、それらは最初のスキャンと解析の過程で事前に作成されます。

したがって、関数を事前に定義するかどうかを検討するときは、パフォーマンスについて心配する必要はありません。指導原則は、代わりにプログラムの読みやすさと構造でなければなりません。

あなたがいる限り、それはthisを使用していないとして、機能を事前に定義したいならば、クラス外に定義することを検討:

function filterFunc(item) { return item.val < MAX; } 

class A { 
    process() { 
    const filtered = source.filter(filterFunc); 

あなたは現代のJSで、その後、」this`を必要とした場合はあなたが

class A { 
    constructor() { this.filterFunc = this.filterFunc.bind(this); } 

    process() { 
    const filtered = source.filter(this.filterFunc); 
を書く作る this.filterFunc結合を心配するのではなく、

class A { 
    filterFunc(item) { return item.val < this.MAX; } 

    process() { 
    const filtered = source.filter(item => this.filterFunc(item)); 

を書くことが望ましいです他の回答で述べたようにthisがすでにインスタンスにバインドされているよう

class Test { 
    // constructor etc. 
    step = x => x + this.currentStep; 
    process() { 
     return this.arr.map(step); 
    } 
} 

は、あなたの意図した動作を実現するための簡潔な方法になりますが

1

、それは第2段階にまだあるパブリッククラスのフィールドを必要とするためではありませんまだ、トランスバータなしの多くのブラウザでサポートされています。

あなたが手動で事前に自分の関数をバインドする必要はありませんので、あなたは常に、このようmapfilterなどの機能の第2引数にthisスコープを渡すことができることを覚えておくことは良いです。コードは、これはあなたの関数が正しいスコープを持っていることを確認しながら、あなたが考えている解決策に非常に近い

class Test { 
    // constructor etc. 
    step(x) { return x + this.currentStep; } 
    process() { 
     return this.arr.map(step, this); 
    } 
} 

になります。

ブラウザの内部動作についてはあまりよくわかりませんが、コードが十分に熱く(頻繁に実行されている)、最適化されたコンパイラでは実行するたびにそれらの匿名関数を再作成する必要はないと思います。

関連する問題