我应该在Angular的类中编写方法作为箭头函数

时间:2017-08-25 12:40:19

标签: angular typescript ecmascript-6

在Angular中,技术上可以将类方法编写为ES2015箭头函数,但我从未见过有人这样做过。以这个简单的组件为例:

@Component({
  selector: 'sample'
})
export class SampleComponent {
  arrowFunction = param => {
    // Do something
  };
  normalFunction(param) {
    // Do something
  }
}

这没有任何问题。有什么不同吗?为什么我应该或不应该使用它?

3 个答案:

答案 0 :(得分:17)

this React answer中的点在Angular,任何其他框架或vanilla JavaScript / TypeScript中仍然有效。

类原型方法是ES6,类箭头方法不是。箭头方法属于class fields proposal,而不是现有规范的一部分。它们在TypeScript中实现,也可以使用Babel进行转换。

通常优先使用原型method() { ... }而不是箭头method = () => { ... },因为它更灵活。

回调

arrow方法提供的唯一真正机会是它可以无缝地用作回调:

class Class {
  method = () => { ... }
}

registerCallback(new Class().method);

如果原型方法应该用作回调,它应该另外绑定,这应该最好在构造函数中完成:

class Class {
  constructor() {
    this.method = this.method.bind(this);
  }

  method() { ... }
}

registerCallback(new Class().method);

bind-decorator这样的装饰器可用于TypeScript和ES Next,以便在构造函数中提供更简洁的方法绑定替代方法:

import bind from 'bind-decorator';

class Class {
  @bind
  method() { ... }
}

继承

箭头方法也限制子类使用箭头方法,否则它们不会被覆盖。如果忽略箭头,这会产生问题:

class Parent {
  method = () => { ... }
}

class Child extends Parent {
  method() { ... } // won't override Parent method
}

在儿童课程中无法使用super.method(),因为super.method指的是Parent.prototype.method,但不存在:

class Parent {
  method = () => { ... }
}

class Child extends Parent {
  method = () => {
    super.method(); // won't work
    ...
  }
}

混入

原型方法可以有效地用于mixins。 Mixins可用于多重继承或修复TypeScript方法可见性中的问题。

由于箭头方法在类原型上不可用,因此不能从课外到达:

class Parent {
  method = () => { ... }
}

class Child extends OtherParent { ... }
Object.assign(Child.prototype, Parent.prototype) // method won't be copied

测试

原型方法提供的一个有价值的特性是它们可以在类实例化之前访问,因此它们可以在测试中进行间谍或模拟,即使它们在构造后立即被调用:

class Class {
  constructor(arg) {
    this.init(arg);
  }

  init(arg) { ... }
}

spyOn(Class.prototype, 'init').and.callThrough();
const object = new Class(1);
expect(object.init).toHaveBeenCalledWith(1);

当方法是箭头时,这是不可能的。

TL; DR:原型和箭头类方法之间的选择似乎是一种品味问题,但实际上使用原型方法更具有远见卓识。您通常可能希望避免箭头类方法,除非您确定它们不会造成任何不便。如果您将它们作为回调传递,请不要忘记在原型方法上使用bind

答案 1 :(得分:2)

类箭头函数的一个很好的用例是当你想将一个函数传递给另一个组件并在函数中保存当前组件的上下文时。

@Component({

   template:`
        I'm the parent
       <child-component></child-component>

  `
})
export class PerentComponent{

   text= "default text"
   arrowFunction = param => {
    // Do something
    // let's update something in parent component ( this)

    this.text = "Updated by parent, but called by child"
  };
}

@Component({

   template:`
        I'm the child component

  `
})
export class ChildComponent{
   @Input() parentFunction;

   ngOnInit(){
      this.parentFunction.()
   }
}

 <parent-component></parent-component>

在上面的示例中,child能够调用父组件的功能,并且文本将被正确更新,就像我只是将父项更改为:

export class PerentComponent{

   text= "default text"
   arrowFunction (){
    this.text = "This text will never update the parent's text property, because `this` will be child component  "
  };
}

答案 2 :(得分:1)

只有一种情况,如果你需要进行AOT编译,你必须避免使用箭头功能,如记录here

  

配置模块时,不能使用箭头功能。

     

❌DONT:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Routes, RouterModule } from '@angular/router';

@NgModule({
  imports: [
    BrowserModule,
    RouterModule,
    HttpModule,
    RouterModule.forRoot([], { errorHandler: (err) => console.error(err) })
  ],
  bootstrap: [
    AppComponent
  ],
  declarations: [
    AppComponent
  ]
})
export class AppModule {}
     

✅DO:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Routes, RouterModule } from '@angular/router';

function errorHandler(err) {
  console.error(err);
}

@NgModule({
  imports: [
    BrowserModule,
    RouterModule,
    HttpModule,
    RouterModule.forRoot([], { errorHandler })
  ],
  bootstrap: [
    AppComponent
  ],
  declarations: [
    AppComponent
  ]
})
export class AppModule {}