2016-08-19 44 views
1

我和我的同事曾多次討論過這個問題。有兩種方法來定義類方法。第一種方式是通過函數聲明類方法的函數聲明或表達式?

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

函數聲明往往更容易閱讀。 Action的每個實例只使用一個函數對象,因此它們也更友善。

第二個是與函數表達

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 B extends A { 
    private oldFn2 = this.fn2; 

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

這只是看起來可怕:

class A { 
    fn1() {} 

    fn2() {} 
} 

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

有一個
因爲它的原型的屬性,而不是一部分,你需要做的是這樣有幾個理由更喜歡使用bind方法而不是匿名函數。我覺得它更隱含,因爲它是精確相同的功能,但綁定到特定的this。另一方面,在匿名函數中,除了調用實際函數外,還可以添加更多代碼。

另一件事是,bind功能讓你不僅哪個對象將被視爲this,而且還綁定參數綁定:

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

fn兩個調用這裏是相同的。
你可以用匿名函數做到這一點,但並非總是如此:

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

喜歡「綁定」有什麼好處嗎?我想你不必擔心明確處理和傳遞參數。 – Craxal