2016-08-19 41 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