React 中的 ‘this’ 是什么

本文翻译自 Trey 的这篇文章,并进行了略微修改。

如果你刚接触 React,你可能和我一样会被关键字 this 的使用搞糊涂。本文介绍了 JavaScript 以及 React 中 this 关键字的含义,以及更重要地,我们为什么时刻都在使用它。

this 关键字

根据使用的上下文不同,this 关键字通常会引用一个 JavaScript 元素。让我们举几个例子来说明这一点。

全局的 this 作用域

最直观的作用域就是在你浏览器中的全局作用域,如果你在浏览器中打开控制台,并输入以下内容:

this

……浏览器就会返回位于全局的 Window 对象:

Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, …}

你在 Window 对象中执行的任何指令,均等价于你在全局作用域中使用 this 关键字来执行:

this.alert('嘿!')
// 等价于
Window.alert('嘿!')

this.location = 'https://dgideas.net'
// 等价于
Window.location = 'https://dgideas.net'

函数中的 this 作用域

从这里开始事情有点复杂了,你最好首先了解作用域(Scope)的具体含义。

在 JavaScript 的函数中,this 的值由函数的调用方式决定。调用(Call)、应用(Apply)以及绑定(Bind)等方法能够显式地设定函数中 this 的值。然而,如果没有显式地设置 this,那么 this 将默认为全局上下文:

const thisFunction = function () {
    return this;
}
// 在浏览器中调用 thisFunction() 将返回 Window 对象

在使用严格模式(Strict Mode)时,函数中的 this 将引用它的显式值,如果 this 没有被显式设置,那么 this 的值将会是未定义的:

const strictFunction = function() {
    'use strict';
    return this;
}
// 在浏览器中调用 strictFunction() 将返回 undefined,因为这不是通过调用、应用或绑定来明确设置的

通过调用、应用、绑定和箭头函数明确设置 this

那么,我们如何在函数上显式地设置 this 呢?调用、应用和绑定方法为我们做了这些工作。

函数的 call 方法接受 this 将引用的对象,以及函数中定义的其他参数。而 apply 方法接受 this 将引用的对象,以及一个包含定义函数时引用的参数的数组:

const object = {
    a: 5,
    b: 7
}

const thisFunction = function(c, d) {
    return this.a + this.b + c + d;
}

thisFunction.call(object, 12, 4);
// 返回 28

thisFunction.apply(object, [3, 6]);
// 返回 21

bind 方法与 call 方法或者 apply 方法有显著不同,它将 this 要指代的对象附加在一个函数上。这样,每当这个函数被调用,this 就指向了预先绑定的对象上:

const object = {a: 2, b: 3, c: 6};

const thisFunction = function() {
    return this.a + this.b + this.c;
}

const bindFunction = thisFunction.bind(object);

bindFunction(); // 返回 11

对象上下文

特别地,当我们在一个对象中使用 this 时,它指向的是对象本身。这使得在对象的方法中很容易引用对象的值:

const object = {
    a: 2,
    b: 3,
    thisFunction: function() {
       return this.a + this.b;
    }
};

object.thisFunction() // 返回 5

这对 React 意味着什么

在 React 的组件(component)类中,我们定义的方法能够引用类的属性,如 propsstate。而为了让我们的方法能够访问 this.state 和 this.props,我们需要将React组件的 this 上下文绑定到这些方法。

import React, {Component} from ‘react’;

class App extends Component {
    constructor(props) {
        super(props);
        this.clickFunction = this.clickFunction.bind(this);
    }

    clickFunction() {
        console.log(this.props.value);
    }

    render() {
        return(
          <div onClick={this.clickFunction}>Click Me!</div>
        );
    }
}

this 绑定到类的方法中能够让我们通过组件中形如 this.props 以及 this.state 的方法访问 propsstate

箭头函数

我们注意到,将 this 绑定到类方法中可以构建出许多不同种的样板。自 ES6 中引入的箭头函数是一种已经绑定了当前 this 上下文的函数。由于这个有趣的特性,我们可以将公共类字段自动地绑定在我们的方法中:

const myFunction = () => {
 return this.props.a + this.props.b;
}

// 上述代码等价于...

const myFunction = function() {
  return this.props.a + this.props.b;
}.bind(this);

通过将箭头函数和公共类字段进行结合,我们可以得到构建 React 组件的一种简洁、声明式的方式。

总结

  • 除非使用箭头函数,否则我们需要显式地为函数上下文绑定 this 对象
  • callapplybind 是三种不同的显式设置 this 的方法