Можно ли использовать функцию стрелки в конструкторе реагирующего компонента?

Этот вопрос похож на При использовании React Предпочтительнее использовать функции толстых стрелок или связывать функции в конструкторе?, но немного отличается. Вы можете привязать функцию к this в конструкторе или просто применить функцию стрелки в конструкторе. Обратите внимание, что я могу использовать только синтаксис ES6 в своем проекте.

1.

class Test extends React.Component{
  constructor(props) {
    super(props);

    this.doSomeThing = this.doSomeThing.bind(this);
  }

  doSomething() {}
}

2.

class Test extends React.Component{
  constructor(props) {
    super(props);

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

Каковы плюсы и минусы этих двух способов? Спасибо.

Ответ 1

Вариант 1, как правило, более предпочтительно по определенным причинам.

class Test extends React.Component{
  constructor(props) {
    super(props);

    this.doSomeThing = this.doSomeThing.bind(this);
  }

  doSomething() {}
}

Прототипный метод более прост в распространении. Класс Child может переопределять или расширять doSomething с помощью

doSomething() {
  super.doSomething();
  ...
}

Когда свойство экземпляра

this.doSomeThing = () => {};

или поле класса ES.next

doSomeThing = () => {}

вызов super.doSomething() невозможен, потому что метод не был определен на прототипе. При переопределении это приведет к назначению свойства this.doSomeThing дважды, в родительских и дочерних конструкторах.

Прототипные методы также доступны для методов микширования:

class Foo extends Bar {...}
Foo.prototype.doSomething = Test.prototype.doSomething;

Прототипные методы более проверяемы. Их можно шпионить, обрезать или высмеивать до создания экземпляра класса:

spyOn(Foo.prototype, 'doSomething').and.callThrough();

Это позволяет в некоторых случаях избегать условий гонки.

Ответ 3

Подход 1 более читабельен для меня и более идиоматичен.

Кроме того, объявляя методы внутри класса вместо конструктора, методы могут использоваться совместно.

class Foo {
  test() {}
}

const f1 = new Foo()
const f2 = new Foo()
f1.test === f2.test // true

В подходе 2 вы будете объявлять все методы каждый раз, когда вы создаете новый экземпляр:

class Foo {
  constructor() {
    this.test = () => {}
  }
}

const f1 = new Foo()
const f2 = new Foo()
// the method is not shareable
f1.test === f2.test // false

Теоретически подход 2 медленнее, но влияние на производительность должно быть незначительным.

Я просто пойду на подход 1, поскольку он использовался в React documentation, также я никогда не видел, чтобы кто-либо использовал подход 2.


Я просто запустил несколько образцов для проверки производительности. В последнем Chrome (Mac) объявления методов в конструкторе примерно на 90% медленнее, чем использование bind в конструкторе.

Ответ 4

Проверьте это:

https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&targets=&browsers=&builtIns=false&debug=false&code=class%20Dog%20%7B%0A%20%20constructor()%20%7B%0A%20%20%20%20%0A%20%20%20%20this.cat%20%3D%20_%3D%3E%20%7B%0A%20%20%20%20%20%20this%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D

Мы можем видеть переходы babel

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

в

var _this = this;
this.doSomething = function() { _this }

edit: Я неправильно читаю ваш пост, но приведенное выше все еще верно и интересно. @CodinCat указывает на важную вещь: объявление функции внутри конструктора означает, что требуется время (хотя и очень мало), чтобы добавить эту функцию к объекту при его создании, а также, вероятно, занимает память, поскольку экземпляры этого класса не разделяют такой же метод doSomeThing.

edit2: привязка (эта) к функции фактически вызывает точные проблемы, перечисленные выше. Другими словами, два метода почти одинаковы.