学习bind源代码,比较bind的方式绑定函数在在内存使用上优于箭头函数

前言

使用ES的class,到底是使用箭头函数更有效率,还是在构造器函数(constructor)中使用bind函数给函数绑定context更加有效率?在Demystifying Memory Usage using ES6 React Classes文章中,给出了如下的结论。

上图是在class中使用箭头函数创建类的方法。作者称其为class properties. 可以看得出,使用箭头函数在类中定义的handler方法,在其的每一个实例中都会有一个独立的handler函数。当实例的数量不多的时候,这种方式不会带来很大的内存浪费,但当实例成千上万的时候,这种方式就会显得在内存使用上效率很低。若是能够共享类上的handler岂不是更好。

而使用构造器函数绑定,则能够更加有效的减少内存的使用。通过在构造器函数里面绑定函数,如下代码:

class MyClass extends Component {
  constructor() {
    super();
    this.state = { clicks: 0 };
    this.handler = this.handler.bind(this);
  }
  handler() {
    this.setState(({ clicks }) => ({ clicks: clicks + 1 }));
  }
  render() {
    const { clicks } = this.state;
    return(
      <button onClick={this.handler}>
        {`You've clicked me ${clicks} times`}
      </button>
    );
  }
}
复制代码

每一个实例里面虽然都有handler方法(this.handler,不是MyClass.prototype.handler),但每个实例中的this.handler实际上都共享MyClass.prototype.handler的函数体。

那么这是如何做到的呢? Bind函数MDN Polyfill实现:

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) { //oThis 代表object this
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this, //
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // 维护原型关系
    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}
复制代码

从上面的代码可以看出,我们在构造器中使用bind绑定函数以后,实际上返回了一个函数(fBound),所返回的函数的函数体和待绑定(MyClass.prototype.handler)的函数体是不同的。所返回的函数只是在函数体内调用了待绑定的函数。换句话说,通过在构造器中使用bind绑定函数以后,所生成的实例中,都会有一个独立的fBound,函数体相对于待绑定的函数较小,而每个实例中的fBound在被调用时都会共享待绑定的函数(MyClass.prototype.handler)

结论

通过对比可以发现,使用构造器bind的方法,每个实例都可以有效地共享函数体,从而更加有效的使用内存。但当要绑定的函数较多时,这种方法又显得相对的枯燥和无聊。所以,我认为在知道实例不多,函数体不大的前提下,使用箭头函数更加快捷。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值