ES6 类中的 ES6 函数、箭头函数和“this" [英] ES6 functions, arrow functions and 'this' in an ES6 class

查看:48
本文介绍了ES6 类中的 ES6 函数、箭头函数和“this"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

class App 扩展组件 {构造函数(道具){...}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}`;}使成为() {返回 (<div><form onSubmit={this.onSubmit}><输入值={this.state.term} onChange={this.onChange}/><button>搜索!</button></表单>

);}}

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

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

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

使用 this.onSubmit.bind(this) 吗?

解决方案

了解以下语法很重要:

class A {方法 = () =>{}}

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

class A {构造函数(){this.method = () =>{}}}

注意:此语法还不是 JavaScript 语言的正式部分(目前处于第 3 阶段) 所以你必须使用 像 Babel 这样的转译器来处理它.

methodthis 的值是 A 类,因为这是 this 在构造函数(因为箭头函数从它们定义的范围):

class A {构造函数(){this.method = () =>这个;}}const 实例 = new A();console.log(instance.method() === 实例);//真

在类上定义一个常规(非箭头函数)方法会在类原型(不是实例)上创建一个方法,但没有对 this 将是什么设置任何规则(因为 this 在 JS 中是动态的,取决于函数如何被调用,而不是如何定义).

class A {方法() {}}console.log(new A().method === A.prototype.method);//真

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

class A {构造函数(){this.methodOnInstance = () =>这个;}methodOnPrototype() { 返回这个;}}const 实例 = new A();控制台日志(instance.methodOnInstance() === instance.methodOnPrototype(),//真instance.methodOnPrototype() === 实例//真);

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

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

这在 React 中也发生在所有(合成)DOM 事件处理程序中.

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

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

class A {构造函数(){this.methodOnInstance = this.methodOnPrototype.bind(this);}methodOnPrototype() { 返回这个;}}const 实例 = new A();控制台日志(instance.methodOnInstance() === instance.methodOnPrototype(),//真instance.methodOnPrototype() === 实例//真);

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

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

class A {构造函数(){this.method = this.method.bind(控制台);}方法(){返回这个;}}const 实例 = new A();控制台日志(instance.method() === 控制台//真);

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>
    );
  }
}

What is the difference between the two type of functions declared in the class (onChange and onSubmit). I get an error on referencing this.sate in const url if I declare it as an ES6 class method but changing it to arrow function fixes it.

I want to know how exactly 'this' is handled in both the cases

Also, how do I do it the other way? Say, if I want to use the same onSubmit function (ES6 class method) but want to handle this when I call it (in the form element), how do I do it ?

Using this.onSubmit.bind(this) ?

解决方案

It's important to know that this syntax:

class A {
  method = () => {}
}

is just syntactic sugar for creating an instance method in the class constructor:

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

Note: This syntax is not an official part of the JavaScript language yet (currently in stage 3) so you must use a transpiler like Babel to handle it.

The value of this within method is the class A because that is what this points to in the constructor (since arrow functions inherit the context from the scope they are defined in):

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

const instance = new A();
console.log(instance.method() === instance); // true

Defining a regular (non-arrow function) method on the class creates a method on the class prototype (not instance) but sets no rules on what this will be (since this is dynamic in JS and depends on how a function is called, not how it's defined).

class A {
  method() {}
}

console.log(new A().method === A.prototype.method); // true

If methods defined in either of these ways are called on the class instance (via the .), as per the rule of how this is bound when a function is called as a method of an object, this will point to the class instance in both cases:

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

const instance = new A();
console.log(
  instance.methodOnInstance() === instance.methodOnPrototype(), // true
  instance.methodOnPrototype() === instance // true
);

One major difference between the two method declarations above is that the instance method has this always fixed to the class instance while the class (prototype) method does not (we can change it by using Function.prototype.apply or Function.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
);

A common occurrence where the this changes is within an event handler, where the event handler calls the function passed into it and binds the context to the element on which the event happened (so overrides the value of this to be the element that was clicked or whatever the event was)

This happens in React as well for all (synthetic) DOM event handlers.

Therefore, if we want our method's context to always point to the instance of the React component, we can use the instance method.

Another way of restricting the context but not using the special instance method syntax that requires Babel is to directly create an instance method ourselves by creating a new function from the class (prototype) method with a bound context (using Function.prototype.bind):

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
);

This allows us to arrive to the same result as using the special instance method syntax but with the currently available tools (ES2017 and under).

If for some reason we want a method that is always bound to something that is not an instance of the class, we can do that as well:

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

const instance = new A();
console.log(
  instance.method() === console // true
);

这篇关于ES6 类中的 ES6 函数、箭头函数和“this"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆