2016-08-19 12 views
1

私の同僚と私はこの議論を何度かしてきました。クラスメソッドを定義するには2つの方法があります。最初の方法は、関数宣言である:クラスメソッドの関数宣言または式ですか?

class Action { 
    public execute(): void { 
     this.doSomething(); 
    } 
    ... 
} 

関数宣言が読みやすくなる傾向があります。 Actionのインスタンスごとに1つの関数オブジェクトのみが使用されるため、メモリにもやさしくなります。

表現機能である:

class Action { 
    public execute:() => void =() => { 
     this.doSomething(); 
    }; 
    ... 
} 

関数式は、(特にタイプ定義を持つ)より多くの入力を必要とする、読んで、そしてActionのすべてのインスタンスのための新しい関数オブジェクトを生成することが困難です。そしてたくさんのオブジェクトを生成しているなら、それは悪いことです。

しかし、関数式は一つの小さな利益を持っている:彼らはthisのコンテキスト(すなわちActionインスタンス)を保持するそれらを呼び出すどんなに:これで期待どおりに関数式が機能するよう

var instance = new Action(); 
setTimeout(instance.execute); 

の方法が宣言場合。関数の宣言は無残に失敗、しかし、彼らは簡単に代わりにこれを行うことによって固定することができます:だから

var instance = new Action(); 

setTimeout(() => instance.execute()); 
// or 
setTimeout(instance.execute.bind(instance)); 

、一方が他方の上に、より良い習慣と考えられている、または優先/この純粋な状況でしょうか?

答えて

3

私の意見では、this(たとえば、イベントハンドラとして渡された場合)の別のコンテキストで関数が呼び出される可能性があることがわかっている場合にのみ、矢印メソッドをクラスメソッドとして使用する必要があります。 Function.prototype.bindを使用しないでください。

あなたが書いたように、コードの可読性を含むいくつかの理由がありますが、主な理由は継承のためです。 あなたは矢印の機能を使用する場合、あなたは、単にメンバーとしてインスタンスに機能を割り当てるが、関数はプロトタイプに追加されません:あなたはこのクラスを拡張したい場合は

// ts 
class A { 
    fn1() {} 

    fn2 =() => {} 
} 

// js 
var A = (function() { 
    function A() { 
     this.fn2 = function() { }; 
    } 
    A.prototype.fn1 = function() { }; 
    return A; 
}()); 

だから何が起こるとfn2メソッドをオーバーライドしますか?

class A { 
    fn1() {} 

    fn2() {} 
} 

class B extends A { 
    fn2() { 
     super.fn2(); 
    } 
} 

がありますと比較したときにだけひどい見えます

class B extends A { 
    private oldFn2 = this.fn2; 

    fn2 =() => { 
     this.fn2(); 
    } 
} 

:それは、プロトタイプのプロパティではなく一部ですので
、あなたのような何かをする必要があります匿名機能よりもbindメソッドを使用するほうが好ましい理由はほとんどありません。 正確なと同じですが、特定のthisにバインドされているため、より暗黙的です。一方、無名関数では、実際の関数を呼び出す以外のコードを追加できます。fn

function fn(one, two, three) {} 
fn.bind(null, 1, 2)(3); 
fn(1, 2, 3); 

2つの呼び出しはここに同じです。

もう一つは、bind機能がthisと見なされるオブジェクトが、また、パラメータをバインドすることができないだけでバインドできることです。
あなたは常にではない、無名関数でそれを行うことができますが、:

var a = ["zero", "one", "two", "three", "four", "five"]; 
function fn(value, index) { 
    console.log(value, index); 
} 

// works 
a.forEach((item, index) => { 
    setTimeout(() => { 
     fn(item, index); 
    }, 45); 
}); 

// works 
for (let i = 0; i < a.length; i++) { 
    setTimeout(() => { 
     fn(a[i], i); 
    }, 45); 
} 

// doesn't work as i is undefined when the function is invoked 
for (var i = 0; i < a.length; i++) { 
    setTimeout(() => { 
     fn(a[i], i); 
    }, 45); 
} 

// works because the value of i and the value of a[i] are bound 
for (var i = 0; i < a.length; i++) { 
    setTimeout(fn.bind(null, a[i], i), 45); 
} 
+0

素晴らしいです。継承/プロトタイプのシナリオも考慮していませんでした。メソッドがイベントハンドラとして使用されても、上記のように匿名関数ラッパーを使用してほとんどの状況を緩和することができます。 – Craxal

+0

@Craxal私は匿名のものの代わりに 'bind'関数を使うのが好きですが、いずれの場合もそうではありません。 –

+0

'bind 'を好むことにはどんな利点がありますか?明示的に引数を処理して渡すことについて心配する必要はありません。 – Craxal

関連する問題