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

时间:2016-02-21 10:12:44

标签: javascript ecmascript-6 react-native

我正试图围绕ES6中Classes的语法。同时通过Bonnie Eisenman的Learning React Native学习Fabric本土。

当回调是一个Class“方法”时,我遇到了一个关于在回调中访问this的问题。我知道在StackOverflow上已经多次提出了回调中词法this的问题。例如在 How to access the correct `this` context inside a callback?

根据我的在线研究,我遇到了一个解决方案。但我不确定这是在ES6中这样做的正确方法。

当我尝试以下内容时,我的问题出现了:

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

如果我这样做,this中的_handleTextChange未定义(无法读取未定义的属性'setState')。我对此感到惊讶。来自其他OO语言,我正在解释,好像这个方法表现得更像是一个静态方法。

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

我真的想弄清楚如何调用类方法。经过一番研究后,我通过以下方式成功实现了这项工作:onSubmitEditing={this._handleTextChange.bind(this)}。也许我误解了JavaScript的一个基本方面(我是JS的初学者),但这对我来说似乎完全是疯了。是否真的无法从方法中访问对象的上下文而没有将对象显式绑定到...它自己的方法,在它被调用的位置?

我还尝试在构造函数中添加var self = this;并在self.setState中调用_handleTextChange。但是,发现它不起作用并不是太惊讶。

当一个对象被称为回调时,从一个方法中访问对象的正确方法是什么?

3 个答案:

答案 0 :(得分:14)

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

所以,他们决定不把这个内置到React的类模型中。如果你想要

,你仍然可以在构造函数中显式预绑定方法
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})
  }

但我们总是有一种简单的方法来避免这种预先绑定。是啊!你说对了。箭头功能。

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

BTW,这都是关于React的。 ES6类总是有一种方法可以从方法中访问对象的上下文,而无需将对象显式绑定到它自己的方法上。

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

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

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

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

但这并不打印&#39; Check 1&#39;如果我们在JSX Expression中调用它。

编辑::正如@Oka所提到的,类体中的箭头函数是ES7 +特性,可在编译器/ polyfill中使用,例如babel。如果您不使用支持此功能的转发器,我们可以如上所述绑定到this或者像这样写一个新的BaseComponent(这是一个坏主意)

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');
 }
 // ...
}

答案 1 :(得分:6)

在常规的旧JavaScript中突破ES6和React一段时间,当你传递一个对象的方法时,它只是对函数本身的引用,而不是对象的函数。

任何调用函数都可以通过正常调用函数来选择使用隐式this,或者甚至可以选择使用.call.apply或{{1来更改上下文}}

.bind

正在发生的事情是,您将var O = { foo: function () { console.log(this); }, bar: 51 }; O.foo(); // `this` is O, the implicit context, inferred from the object host var foo = O.foo; foo(); // `this` is is the global object, or undefined in Strict Mode 函数传递给事件发射器,该事件发射器将在稍后执行。事件发射器不知道它作为方法接收了该函数。它只是执行它。

_handleTextChange

看看上下文共享:

var O = {
  foo: function (event) {
    console.log(this);
    console.log(event);
  },
  bar: 51
};

function invoke (func) { // the function reference held by O.foo is now held by `func`
  func('some param'); // it has no idea as to what the contextual `this` is bound to, maybe its implicitly global, maybe its explicitly bound, maybe its undefined
}

invoke(O.foo);

invoke(O.foo.bind(O)); // A copy of the function with the context explicitly bound

你可以通过这些例子随意复杂化。

答案 2 :(得分:3)

  

也许我误解了JavaScript的一个基本方面(我是JS的初学者),但这对我来说似乎完全是疯了。是否真的无法从方法中访问对象的上下文而没有将对象显式绑定到...它自己的方法,在它被调用的位置?

嗯,“方法”不是由javascript中的对象拥有。所有函数都是一等值(对象),而不是对象或类的“部分”。

调用函数时会发生this value的绑定,具体取决于函数的调用方式。使用方法表示法的函数调用将this设置为接收对象,事件侦听器调用将其this设置为当前事件目标,而普通函数调用仅具有undefined

如果要访问实例上的方法,它实际上只是标准原型继承属性访问,它产生一个函数,然后调用该函数并动态绑定到接收器。

如果要在函数作为事件侦听器时将函数作为方法调用,则需要显式创建执行此操作的函数 - “绑定”方法。在ES6中,箭头符号通常是首选。