浅谈react中bind this的原因

1,194 阅读2分钟

今天看call/apply/bind的区别时,想起当初用react时,render中绑定事件总要把类中的方法bind(this),当初时一知半解,这次一定要弄懂原因

首先我们看react官网说法:

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')
);

我们经常用到的onClick={this.handleClick},需要在contructor显示绑定this,或者用箭头函数定义handleClick,则不需要绑定this,那么这是为什么呢?

实际上这不是react的问题,是javaScript的函数工作原理造成的。

我翻阅MDN上关于class类的描述,找到了原理 MDN链接

在严格模式下通过this传递给一个函数的值不会被强制转换为一个对象。对一个普通的函数来说,this总会是一个对象:不管调用时this它本来就是一个对象;还是用布尔值,字符串或者数字调用函数时函数里面被封装成对象的this;还是使用undefined或者null调用函数式this代表的全局对象(使用call, apply或者bind方法来指定一个确定的this)。这种自动转化为对象的过程不仅是一种性能上的损耗,同时在浏览器中暴露出全局对象也会成为安全隐患,因为全局对象提供了访问那些所谓安全的JavaScript环境必须限制的功能的途径。所以对于一个开启严格模式的函数,指定的this不再被封装为对象,而且如果没有指定this的话它值是undefined:

最后一句话,严格模式下,this如果没有指定的话就是undefined。

当然,这里说的是普通函数,箭头函数的this不会为undefied。为什么箭头函数的this正常呢,因为箭头函数有几个特点,其中: 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

请大声朗读三遍,也就是说,箭头函数定义时this已经指向了当前类,就不会出现普通函数this没有指向的问题。

总结

综上, react bind this问题,根本原因是 :class 类 默认是严格模式,普通函数的this如果不指定就会指向undefined,要在constructor函数中绑定或将类方法写为箭头函数。所以跟react无关,是因为js函数工作原理。