在 ES6 中的 React Class 上定义方法的两种方式有什么区别

What's difference between two ways of defining method on React Class in ES6

我在 ES6 React 代码中经常看到这种情况

class Foo extends React.Component {
  bar = () => {
    console.log("bar")
  }

  baz() {
    console.log("baz")
  }
}

似乎它们都在 Foo 上定义了方法 barbaz,但它们有何不同。

函数的编写方式和 this

context 的声明不同

在第一个语法中

bar = () => {
    console.log("bar")
  }

该函数是使用 Arrow function 语法编写的。

An arrow function does not have its own this; the this value of the enclosing execution context is used. Hence this keyword inside this function will refer to the context of the React class

然而第二个声明

baz() {
    console.log("baz") 
}

是一个简单的函数,这个函数中的this keyword指的是函数本身的上下文。

所以当你尝试像 this.statethis.setState 那样访问 React class Properties/functions 时你会在第二种情况下得到一个错误(如果你没有使用绑定此函数的任何其他地方(示例构造函数)),而它在第一种情况下会起作用,因为对于箭头函数,this 在函数体内和在函数体外的意思相同。这意味着如果您在组件的自定义函数中使用箭头函数,它们可以毫无意外地使用 thisthis.setState

上查看此答案

为简单起见,两者相等:

  1. bar = () => { ... }
  2. this.bar =this.bar.bind(这个)

前面的答案是绝对正确的,这就是为什么你想在 React classes 中使用箭头函数。

我还想指出一个细微的区别,即在 class 中使用它们的潜在陷阱以避免意外...

在 class 上定义的箭头函数 添加到实例中作为 属性 恰好是一个函数,而定义不是箭头函数将 将函数作为方法添加到 class 的原型

在永远不会扩展的 React 组件中,这很好,但是如果出现这种情况,你想要子class 一个组件,你将无法覆盖期望能够调用的箭头函数基础 class 通过 super,你只能完全覆盖它

class Button extends React.PureComponent {

    // class method - overridable in subclass
    pressMethod: function(): void {
      console.log('beep')
    }

    // instance property functions - only overwriteable in subclass
    pressArrow = (): void => {
      console.log('boop')
    }

    pressArrowTwo = (): void => {
      console.log('blip')
    }

  }


  class BigRedButton extends Button {

    // class method - overides subclass one, 
    // can call superclass method via `super`
    pressMethod: function(): void {
      super.pressMethod() // prints 'beep' to console
      console.log('BOOOOOOOOM!!!')
    }

    // instance property function
    // cannot call superclass via `super` as lambda's have no prototype
    pressArrow = (): void => {
      super.pressArrow() // TypeError - not a function
      console.log('BOOOOOOOOM!!!')
    }

    // completely overwrites instance property of same name in subclass
    // doesn't try to access prototype so won't error but is limited
    pressArrowTwo = (): void => {
      console.log('BOOOOOOOOM')
    }

  }