React 中的 this

React 中的 this

一、为事件处理函数绑定上 this

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 为了在回调中使用 `this`,这个绑定是必不可少的
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
      this.setState(state => ({
          isToggleOn: !state.isToggleOn
      }));
  }
  render() {
    return (
      <button onClick={this.handleClick}>
            {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

上面例子来自 react 官网 。为了将 handleClick 函数中的 this 指向 Toogle 组件,我们需要给它手动绑定:this.handleClick = this.handleClick.bind(this)

这时有的小伙伴会问:如果不绑定,它的 this 就不指向 Toogle 组件吗?

确实是这样,如果我们不对它进行绑定,this 打印出来将会是 undefined ,这点将在后面介绍。

可以看到,使用 bind 绑定可以实现我们的目的,但是可能有人不喜欢这种方法。由于函数的声明在 class 中,而绑定则在 constructor 中,一方面,这样会使 constructor 变得臃肿;另一方面,函数一旦多起来,我们就需要在声明之后再回到 constructor 中完成绑定,这样显得比较麻烦,并且容易遗漏。那有没有不需要在 constructor 中手动绑定的方法呢?答案是有的。

方式一:class fields 语法

class LoggingButton extends React.Component {
  // 此语法确保 `handleClick` 内的 `this` 已被绑定。
  // 注意: 这是 *实验性* 语法。
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

方式二:在回调中使用箭头函数

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // 此语法确保 `handleClick` 内的 `this` 已被绑定。
    return (
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}

二、原因解析

有的小伙伴可能注意到了,在后面介绍的两种方式中,都使用到了箭头函数。而箭头函数的 this 是绑定词法作用域的,简单来说,箭头函数的 this 只跟它定义的地方有关,而普通函数的 this 更像是一个动态绑定的过程。由于箭头函数定义在组件中,它自然而然地就指向组件对象了。

那在定义在普通函数中的 this 默认指向什么呢?

答案是:window 对象。

很多小伙伴可能陷入了一个误区:我们将函数传给组件的 onClick ,调用它的不应该是组件对象吗,为什么会是 window 对象?

需要注意的是,我们只是将函数的引用传递给组件,但这并不意味着调用函数的就是组件对象。比如:

function A() {
    this.print = function () {
        console.log(this);
    }
}
var a = new A();
a.print();		// 指向 A 的实例对象
var outerPrint = a.print;
outerPrint();	// 指向 window

由于普通函数的 this 指向更像是一个动态的问题,它取决于函数的调用位置。对于上面这段代码,我们称为 隐式丢失 ,不了解的小伙伴可以查一查 this 的四种绑定规则,这里不做过多介绍。

有的好奇宝宝又会问了:我明白了!这样的话,在之前的普通函数中,默认是指向 window 对象而非组件对象。但是为什么最后打印出来是 undefined 而不是 window 呢?

答案是:严格模式。

严格模式下,全局作用域函数中的 this 指向为 undefined。而 class 则是默认使用了严格模式。

类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。

好耶!又明白一个知识点~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值