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

rod*_*rod 13 javascript ecmascript-6 react-native

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

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

根据我在网上的研究,我遇到了一个解决方案.但我不确定这是在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}/>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

(我只是对本书中的示例进行了略微修改,以匹配ES6类语法和导入/导出语法而不是Require.)

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

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

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

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

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

Pra*_*nth 14

React.createClass(ES5)创建类的方式有一个内置的功能,可以this自动绑定所有方法.但是在引入classesES6并迁移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})
  }
Run Code Online (Sandbox Code Playgroud)

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

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}/>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这都是关于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';
Run Code Online (Sandbox Code Playgroud)

但如果我们在JSX Expression中调用它,则不会打印"Check 1".

编辑::正如@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');
 }
 // ...
}
Run Code Online (Sandbox Code Playgroud)

  • "class"主体中的箭头函数是ES7提议,在Babel等转换器中被认为是_experimental_. (2认同)

Oka*_*Oka 6

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

任何调用函数可以选择使用隐式的this,通过正常调用函数,或者甚至可以选择使用可以更改上下文.call.apply,或.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
Run Code Online (Sandbox Code Playgroud)

发生的事情是,您将_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
Run Code Online (Sandbox Code Playgroud)

看一下上下文共享:

function foo () {
  console.log(this.a);
}

// Both object hold references to the foo function
var O = { foo : foo, a : 5 },
    O2 = { bar : foo, a : 1 };

O.foo(); // implicit `this` from O
O2.bar(); // implicit `this` from O2

var Z = { a : 23 };

O.foo.call(Z); // explicit `this` from Z
Run Code Online (Sandbox Code Playgroud)

您可以通过这些示例随意复杂化.


Ber*_*rgi 5

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

好吧,“方法”不属于javascript 中的对象。所有函数都是一流的值(对象),而不是对象或类的“一部分”。

this的绑定在调用函数时发生,具体取决于调用函数的方式。带有方法符号的函数调用将其this设置为接收对象,事件侦听器调用将其this设置为当前事件目标,而普通函数调用只有undefined.

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

如果您想在实例上调用函数作为事件侦听器的方法,那么您需要显式创建一个执行此操作的函数 - “绑定”方法。在 ES6 中,通常首选箭头符号。