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

Binding context when calling ES6 method. How to access object from within method called as callback?

本文关键字:方法 回调 访问 对象 ES6 绑定 上下文 调用      更新时间:2023-09-26

我正在尝试围绕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}/>
    );
  }
}

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

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

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

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

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

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

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

顺便说一句,这都是关于反应的。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';

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

编辑 :: 正如@Oka提到的,类体中的箭头函数是 ES7+ 功能,在 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');
 }
 // ...
}

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

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

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

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

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

脱离

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

任何调用函数都可以选择使用隐式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

正在发生的事情是,您正在将_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

看看上下文共享:

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

这些例子可能会变得任意复杂。