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

前言

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

class properties

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

constructor bind

而使用构造器函数绑定,则可以更加有效的减小内存的使用。经过在构造器函数里面绑定函数,以下代码:bash

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的函数体。app

那么这是如何作到的呢? 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)ui

结论

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

相关文章
相关标签/搜索