ES6函数,箭头函数和ES6类中的"this"

d_b*_*gar 5 javascript ecmascript-6 reactjs arrow-functions es6-class

class App extends Component {
  constructor(props) {
    ...
  }

  onChange = (e) => this.setState({term: e.target.value})

  onSubmit(e){
    e.preventDefault();
    const api_key = "C1hha1quJAQZf2JUlK";
    const url = `http://api.giphy.com/v1/gifs/search?q=${this.state.term}&api_key=${api_key}`;
  }

  render() {
    return (
      <div>
        <form onSubmit={this.onSubmit}>
          <input value={this.state.term} onChange={this.onChange}/>
          <button>Search!</button>
        </form>
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

在类中声明的两种类型的函数(onChange和onSubmit)之间有什么区别.我在const url中引用this.sate时出错,如果我将其声明为ES6类方法但将其更改为箭头函数则修复它.

我想知道在这两种情况下如何处理"这个"

另外,我该怎么做呢?比方说,如果我想使用相同的onSubmit函数(ES6类方法),但是当我调用它时(在表单元素中)想要处理它,我该怎么做?

使用this.onSubmit.bind(this)

nem*_*035 10

知道这个语法很重要:

class A {
  method = () => {}
}
Run Code Online (Sandbox Code Playgroud)

只是用于在类构造函数中创建实例方法的语法糖:

class A {
  constructor() {
    this.method = () => {}
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:此语法尚未成为JavaScript语言的官方部分(目前处于第3阶段),因此您必须使用像Babel这样的转换程序来处理它.

thiswithin 的值method是类,A因为这是this构造函数中指向的内容(因为箭头函数从它们定义的范围继承上下文):

class A {
  constructor() {
    this.method = () => this;
  }
}

const instance = new A();
console.log(instance.method() === instance); // true
Run Code Online (Sandbox Code Playgroud)

在类上定义一个常规(非箭头函数)方法会在类原型(不是实例)上创建一个方法,但不会对this将要设置的内容设置规则(因为this在JS中是动态的,并且取决于函数的调用方式,而不是它是如何调用的定义).

class A {
  method() {}
}

console.log(new A().method === A.prototype.method); // true
Run Code Online (Sandbox Code Playgroud)

如果在类实例(通过.)this上调用以这两种方式中定义的方法,则根据在将函数作为对象的方法调用时如何绑定的规则,this将指向两种情况下的类实例:

class A {
  constructor() {
    this.methodOnInstance = () => this;
  }
  methodOnPrototype() { return this; }
}

const instance = new A();
console.log(
  instance.methodOnInstance() === instance.methodOnPrototype(), // true
  instance.methodOnPrototype() === instance // true
);
Run Code Online (Sandbox Code Playgroud)

上面两个方法声明之间的一个主要区别是实例方法this 总是固定到类实例而类(原型)方法没有(我们可以通过使用Function.prototype.applyFunction.prototype.call来更改它)

class A {
  constructor() {
    this.methodOnInstance = () => this;
  }
  methodOnPrototype() { return this; }
}

const instance = new A();
console.log(
  instance.methodOnInstance() === instance.methodOnPrototype(), // true
  instance.methodOnPrototype.call('new this') === 'new this' // true
);
Run Code Online (Sandbox Code Playgroud)

this更改在事件处理程序中的常见情况,其中事件处理程序调用传递给它的函数并将上下文绑定到发生事件的元素(因此会覆盖作为this被单击的元素的值或者任何事件是)

这种情况发生在React以及所有(合成)DOM事件处理程序中.

因此,如果我们希望方法的上下文始终指向React组件的实例,我们可以使用实例方法.

限制上下文但不使用需要Babel的特殊实例方法语法的另一种方法是通过使用绑定上下文(使用Function.prototype.bind)从类(prototype)方法创建新函数来直接创建实例方法:

class A {
  constructor() {
    this.methodOnInstance = this.methodOnPrototype.bind(this);
  }
  methodOnPrototype() { return this; }
}

const instance = new A();
console.log(
  instance.methodOnInstance() === instance.methodOnPrototype(), // true
  instance.methodOnPrototype() === instance // true
);
Run Code Online (Sandbox Code Playgroud)

这允许我们得到与使用特殊实例方法语法相同的结果,但使用当前可用的工具(ES2017及以下).

如果由于某种原因我们想要一个总是绑定到不是该类实例的方法的方法,我们也可以这样做:

class A {
  constructor() {
    this.method = this.method.bind(console);
  }
  method() { return this; }
}

const instance = new A();
console.log(
  instance.method() === console // true
);
Run Code Online (Sandbox Code Playgroud)