Methods 类方法的函数声明或表达式?
我和我的一位同事已经讨论过好几次了。定义类方法有两种方法。第一种方法是使用函数声明: 函数声明往往更易于阅读。每个动作实例只使用一个函数对象,因此它们对内存更友好 第二个是函数表达式: 函数表达式需要更多的类型,尤其是类型定义,更难阅读,并且为每个操作实例生成一个新的函数对象。如果你正在生成很多很多的对象,那就不好了 但是,函数表达式有一个小小的好处:它们保留了该实例的上下文,即操作实例,无论谁调用它们:Methods 类方法的函数声明或表达式?,methods,typescript,function-declaration,Methods,Typescript,Function Declaration,我和我的一位同事已经讨论过好几次了。定义类方法有两种方法。第一种方法是使用函数声明: 函数声明往往更易于阅读。每个动作实例只使用一个函数对象,因此它们对内存更友好 第二个是函数表达式: 函数表达式需要更多的类型,尤其是类型定义,更难阅读,并且为每个操作实例生成一个新的函数对象。如果你正在生成很多很多的对象,那就不好了 但是,函数表达式有一个小小的好处:它们保留了该实例的上下文,即操作实例,无论谁调用它们: var instance = new Action(); setTimeout(insta
var instance = new Action();
setTimeout(instance.execute);
在本例中,声明为函数表达式的方法按预期工作。函数声明失败得很惨,但这样做很容易修复它们:
var instance = new Action();
setTimeout(() => instance.execute());
// or
setTimeout(instance.execute.bind(instance));
那么,是一个被认为比另一个更好的实践,还是这纯粹是情境性的/优先的?在我看来,只有当您确定如果函数作为事件处理程序传递,并且希望避免使用时,才应该使用arrow函数作为类方法 这有几个原因,如您所写,包括代码可读性,但主要原因是继承。 如果使用箭头函数,则只需将函数作为成员分配给实例,但该函数不会添加到原型中:
// 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方法。我发现它更含蓄,因为它是完全相同的函数,但绑定到一个特定的函数。另一方面,在匿名函数中,除了调用实际函数之外,还可以添加更多代码
另一件事是,bind函数不仅允许您绑定将被视为以下对象的对象,还允许您绑定参数:
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);
}
在我看来,箭头函数应该作为类方法使用,前提是您确实知道,如果它作为事件处理程序传递,则可能会使用不同的上下文来调用该函数,例如,您希望避免使用 这有几个原因,如您所写,包括代码可读性,但主要原因是继承。 如果使用箭头函数,则只需将函数作为成员分配给实例,但该函数不会添加到原型中:
// 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方法。我发现它更含蓄,因为它是完全相同的函数,但绑定到一个特定的函数。另一方面,在匿名函数中,除了调用实际函数之外,还可以添加更多代码
另一件事是,bind函数不仅允许您绑定将被视为以下对象的对象,还允许您绑定参数:
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);
}
杰出的我甚至没有考虑过继承/原型场景。即使某个方法可以用作事件处理程序,我认为大多数情况下都可以使用上述匿名函数包装器来缓解。@Craxal我更喜欢使用绑定函数而不是匿名函数,但在这两种情况下都不太麻烦。首选绑定有什么好处吗?例如,我想你不必担心显式处理和传递参数。我甚至没有考虑过继承/原型场景。即使某个方法可以用作事件处理程序,我认为大多数情况下都可以使用上述匿名函数包装器来缓解。@Craxal我更喜欢使用绑定函数而不是匿名函数,但在这两种情况下都不太麻烦。首选绑定有什么好处吗?例如,我想您不必担心显式处理和传递参数。