[关闭]
@frank-shaw 2017-02-08T02:38:03.000000Z 字数 2291 阅读 1908

【翻译】在React, ES6&ES7中绑定JavaScript的this关键字的6种方法

javaScript


原文链接:https://www.sitepoint.com/bind-javascripts-this-keyword-react/

JavaScript的this关键字会令很多开发者感到很困惑。与其他有明确类模型(即使ES6开始有了class关键字,但是底层实现上依然是原型链模型)的语言不同,JavaScript中的this表示的含义通常是不明确的,当你在处理回调函数的时候,此问题更为突出。

问题描述

因为React在类中使用this关键字来指代component的上下文环境,因此在使用React的时候也存在同样的困惑。在使用React的component时,你可能会看到如下代码:

  1. this.setState({ loading: true });
  2. fetch('/').then(function loaded() {
  3. this.setState({ loading: false });
  4. });

上面这段代码会报错,因为“this.setState is not a function”。这是因为promise的回调函数被调用的时候,函数的内部上下文环境发生了变化,this指向了错误的对象。让我们来看看可以如何来解决这个问题。

解决方案

1.用别的变量来代替this

这种方法在component的作用域顶层,使用了另一个变量来指向this变量:

  1. var component = this;
  2. component.setState({ loading: true });
  3. fetch('/').then(function loaded() {
  4. component.setState({ loading: false });
  5. });

这种方法对于初学者来讲,是较好理解的(即使你有可能不明白为什么这样做可行,但它确实有效)。它给了一个视觉上的保证:你所指向的上下文环境是正确的。

2.绑定this

这种方法需要我们在运行回调函数时候为其注入正确的上下文环境。

  1. this.setState({ loading: true });
  2. fetch('/').then(function loaded() {
  3. this.setState({ loading: false });
  4. }.bind(this));

javascript中的所有函数都包含有bind方法,它允许你指定函数内部的this的指代的具体对象。当一个函数在运行过程中被绑定上下文环境之后,那么它的上下文环境就不允许改变了。

实际上,bind函数仅仅是创建了一个新的函数(该函数指定好了上下文)。源码的简化版(实际上会更加复杂)如下:

  1. Function.prototype.bind = function (scope) {
  2. var fn = this;
  3. return function () {
  4. return fn.apply(scope);
  5. };
  6. }

3.React中的component方法

React允许开发者在component类中定义任意方法(通过React.createClass方法),同时这些方法都会自动添加上合适的上下文。当然,仅仅限制在React.createClass方法内部。

  1. React.createClass({
  2. componentWillMount: function() {
  3. this.setState({ loading: true });
  4. fetch('/').then(this.loaded);
  5. },
  6. loaded: function loaded() {
  7. this.setState({ loading: false });
  8. }
  9. });

在使用React的时候,这当然为开发者省下了不少的精力。它允许你直接使用已经命名的函数。事实上,如果你尝试在component方法中添加.bind(this)方法,React会发出警告说:

bind(): You are binding a component method to the component. React does this for you automatically in a high-performance way, so you can safely remove this call.

不过,需要记住的是:这个自动绑定的功能在ES6中并没有实现(在ES7中可使用)。

4.ES6的箭头函数

箭头函数的引入有两个方面的影响:一是更简短的函数书写,二是对 this 的词法解析(箭头函数会捕获其所在上下文的this值,作为自己的this值)。

  1. this.setState({ loading: true });
  2. fetch('/').then(() => {
  3. this.setState({ loading: false });
  4. });

上面的代码运行起来完全没问题。

当然,箭头函数的一个弊端就是我们无法对我们的函数进行命名了。这会对调试造成一定的困扰。

5.ES7的bind表达式

ES7中有了新的提案:针对bind操作,引入了::作为操作符,具体操作方式为: ::左侧为被操作的数值,右侧为操作的函数。我们对应的表达式可以写成:

  1. this.setState({ loading: true });
  2. fetch('/').then(this::() => {
  3. this.setState({ loading: false });
  4. });

6.特定方法

有一些函数允许将this作为一个特定的变量,放入到表达式中。其中的一个例子就是map函数,允许this值作为它的最后一个参数:

  1. items.map(function(x) {
  2. return <a onClick={this.clicked}>x</a>;
  3. }, this);
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注