调用 ES6 方法时绑定上下文.如何从称为回调的方法中访问对象?

问题描述:

我正在尝试围绕 ES6 中类的语法.同时通过 Bonnie Eisenman 的 Learning React Native 学习 Fabric native.

I'm trying to wrap my head around the syntax for Classes in ES6. While at the same time learning Fabric native through Bonnie Eisenman's Learning React Native.

我遇到了在回调中访问 this 的问题,当该回调是类方法"时.我知道有关回调中的词法 this 问题已在 * 上多次提出.例如在如何在回调中访问正确的`this`上下文?.

I've come accross an issue around accessing this in a callback, when that callback is a Class "method". I'm aware issues around lexical this in callbacks have been raised many times on *. For instance in How to access the correct `this` context inside a callback?.

根据我在网上的研究,我找到了一个解决方案.但我不确定这是在 ES6 中执行此操作的正确方法.

Based on my research online I've come across a solution. But I am not sure this is the correct way to do it in ES6.

当我尝试以下操作时出现了我的问题:

My issue came about when I tried the following below:

class WeatherProject extends Component {
  constructor(props) {
    super(props);
    this.state = {
      zip: ''
    };
  }

  _handleTextChange(event) {
    console.log(event.nativeEvent.text);
    this.setState({zip: event.nativeEvent.text})
  }

  render() {
    return (
      <TextInput
        style={styles.input}
        onSubmitEditing={this._handleTextChange}/>
    );
  }
}

(我只是对书中的示例稍作修改,以匹配 ES6 类语法和导入/导出语法,而不是 Require.)

(Which I've only slightly modified from the example in the book to match the ES6 class syntax and the import/export syntax instead of Require.)

如果我这样做,_handleTextChange 中的 this 是未定义的(无法读取未定义的属性setState").我对此感到很惊讶.来自其他面向对象的语言,我认为这个方法的行为更像是一个静态方法.

If I do this, the this in _handleTextChange is undefined (cannot read property 'setState' of undefined). I was surprised by this. Coming from other OO languages, I'm interpreting as though this method is behaving more as if it was a static method.

我已经能够通过跳过类方法并使用箭头符号来解决这个问题.onSubmitEditing={event =>this.setState({name: event.nativeEvent.text})}.哪个工作正常.我对此没有任何问题或困惑.

I've been able to solve this by skipping the class method and using the arrow notation. onSubmitEditing={event => this.setState({name: event.nativeEvent.text})}. Which works fine. I have no problems or confusion with that.

不过,我真的很想弄清楚如何调用类方法.经过一番研究,我设法通过执行以下操作使其工作:onSubmitEditing={this._handleTextChange.bind(this)}.也许我误解了 JavaScript 的一个基本方面(我是 JS 的初学者),但这对我来说似乎完全疯狂.是否真的没有办法从方法内部访问对象的上下文,而无需将对象显式绑定回......它自己的方法,在它被调用的地方?

I really want to work out how to call a class method though. After a fair bit of research I've managed to make it work by doing the following: onSubmitEditing={this._handleTextChange.bind(this)}. Perhaps I've misunderstood a fundamental aspect of JavaScript (I'm a beginner in JS), but this seems completely insane to me. Is there really no way of accessing the context of an object from within a method without explicitly binding the object back onto... it's own method, at the point where it is called?

我还尝试在构造函数中添加 var self = this; 并在 _handleTextChange 中调用 self.setState.但是发现这不起作用并不奇怪.

I've also tried adding var self = this; in the constructor and calling self.setState in _handleTextChange. But wasn't too surprised to find that didn't work.

当对象作为回调被调用时,从其方法之一访问对象的正确方法是什么?

What's the correct way of accessing an object from within one of its methods when it is called as a callback?

React.createClass (ES5) 创建类的方式有一个内置功能,可以自动将所有方法绑定到 this.但是在 ES6 中引入 classes 并迁移 React.createClass 时,他们发现对于不习惯其他类中的此功能的 JavaScript 开发人员来说可能会有些困惑,或者当他们从对其他类做出反应.

React.createClass (ES5) way of creating class has a built-in feature that bound all methods to this automatically. But while introducing classes in ES6 and migrating React.createClass, They found it can be a little confusing for JavaScript developers that are not used to this feature in other classes, or it can be confusing when they move from React to other classes.

因此,他们决定不将其内置到 React 的类模型中.如果您愿意,您仍然可以在构造函数中显式地预绑定方法

So, they decided not to have this built-in into React's class model. You can still explicitly prebind methods in your constructor if you want like

class WeatherProject extends Component {
  constructor(props) {
    super(props);
    this.state = {
      zip: ''
    };
    this._handleTextChange = this._handleTextChange.bind(this); //Binding to `this`
  }

  _handleTextChange(event) {
    console.log(event.nativeEvent.text);
    this.setState({zip: event.nativeEvent.text})
  }

但我们总是有一个简单的方法来避免这种预绑定.是的!你说对了.箭头函数.

But we always have a simple way to avoid this prebinding. Yeah! You got it. Arrow functions.

class WeatherProject extends Component {
  constructor(props) {
    super(props);
    this.state = {
      zip: ''
    };
  }

  _handleTextChange = event => {
    console.log(event.nativeEvent.text);
    this.setState({zip: event.nativeEvent.text})
  }

  render() {
    return (
      <TextInput
        style={styles.input}
        onSubmitEditing={this._handleTextChange}/>
    );
  }
}

顺便说一句,这都是关于 React 的.ES6 类总是有一种方法可以从方法内部访问对象的上下文,而无需将对象显式绑定回它自己的方法.

BTW, This is all regarding React. ES6 class always has a way of accessing the context of an object from within a method without explicitly binding the object back onto it's own method.

class bindTesting {
  constructor() {
    this.demo = 'Check 1';
  }

  someMethod() {
    console.log(this.demo);
  }

  callMe() {
    this.someMethod();
  }
}

let x = new bindTesting();
x.callMe(); //Prints 'Check 1';

但是如果我们在 JSX 表达式中调用它,它不会打印Check 1".

But this doesn't prints 'Check 1' if we call it in JSX Expression.

EDIT :: 正如@Oka 所提到的,类体中的箭头函数是 ES7+ 特性,可在编译器/polyfills 中使用,如 babel.如果你没有使用支持这个特性的转译器,我们可以像上面提到的那样绑定到 this 或者像这样编写一个新的 BaseComponent(这是一个坏主意)

EDIT :: As @Oka mentioned, arrow functions in class bodies is ES7+ feature and available in Compiler/polyfills like babel. If you're not using transpiler that support this feature, We can just bind to this as mentioned above or write a new BaseComponent like this ( Which is a bad idea )

class BaseComponent extends React.Component {
 _bind(...methods) {
  methods.forEach( (method) => this[method] = this[method].bind(this) );
 }
}

class ExampleComponent extends BaseComponent {
 constructor() {
  super();
  this._bind('_handleTextChange', '_handleClick');
 }
 // ...
}