【build your own xxx】实现你自己的bind函数

简介: 【build your own xxx】实现你自己的bind函数

今天来实现JavaScript的bind函数。 首先看MDN的bind函数描述:

image.png

image.png

从上面可以看出来,var A = B.bind(this)函数其实干了这几件事情:

  1. 返回一个函数,且这个函数后面运行时的this就是bind(this)传入的this
  2. 接收参数,这些参数(如果有的话)作为bind()的第二个参数跟在this(或其他对象)后面,之后它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面
  3. 使用new操作bind函数返回的函数时,之前传入的this会被忽略,也就是说new的优先级高于bind


第一步


首先实现第一步:

Function.prototype.Zbind = function (othis) {
        var originFunc = this;
    return function () {
      originFunc.apply(othis);
    }
  }
  var obj = {
  }
  function createAgumon() {
    this.name = "agumon";
    }
  var createAgumonBind = createAgumon.Zbind(obj);
  createAgumonBind();   
    obj;// {name: "agumon"}
复制代码


第二步


第二步考虑传参的问题,首先看看原生的bind函数是如何传参的:

var obj = {
    }
    function createAgumon(gender, age) {
        this.name = "agumon";
    this.gender = gender;
    this.age = age;
    }
    var createAgumonBind = createAgumon.bind(obj, 'female');
  createAgumonBind(22);
复制代码

可以看出来在bind函数中能先传部分参数,运行bind返回的函数时可以再传入部分参数。 自己实现:

Function.prototype.Zbind = function (othis) {
        var originFunc = this;
    var partArgs = [].slice.call(arguments, 1);
      var func = function() {};
    var boundFunc = function () {
      var finalArgs = partArgs.concat([].slice.call(arguments));
      return originFunc.apply(othis, finalArgs);
        }
        return boundFunc;
    }
    var obj = {
    }
    function createAgumon(gender, age) {
    this.name = "agumon";
    this.gender = gender;
    this.age = age;
    }
  var createAgumonBind = createAgumon.Zbind(obj, 'female');
  createAgumonBind(22);
    obj;// {name: "agumon", gender: "female", age: 22}
复制代码


第三步


使用new来调用bind返回的函数时,会忽略bind传入的thisnew操作和普通的函数调用有哪些区别?粗略的来讲,例如new F()这样的调用,有以下几个步骤:

1. 新建一个对象,var o = new Object()

1. 设置原型链,o.proto = F.prototype

1. 把F函数体内的this绑定为o,并且执行F函数的代码

1. 判断F的返回类型: 如果是值类型,则返回o 如果是引用类型,则返回该引用类型对象

开始实现:

Function.prototype.Zbind = function (othis) {
        var originFunc = this;
    var partArgs = [].slice.call(arguments, 1);
    var func = function() {};
    var boundFunc = function () {
      var finalArgs = partArgs.concat([].slice.call(arguments));
            return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs);
        }
      return boundFunc;
    }
    var obj = {}
    function createAgumon(gender, age) {
      this.name = "agumon";
      this.gender = gender;
      this.age = age;
  }
    var createAgumonBind = createAgumon.Zbind(obj, 'female');
    var newObj = new createAgumonBind(22);
    obj // {}
    newObj // {name: "agumon", gender: "female", age: 22}
复制代码

关键的地方在于这里:this instanceof boundFunc ? this : othis,如果是new操作的话,此时this的__proto__已经指向了boundFunc,所以使用instanceof可以检测出是否在使用new操作


小细节


原型丢失


刚刚实现的Zbind方法有个小问题:

Function.prototype.Zbind = function (othis) {
        var originFunc = this;
        var partArgs = [].slice.call(arguments, 1);
        var func = function() {};
        var boundFunc = function () {
          var finalArgs = partArgs.concat([].slice.call(arguments));
          return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs);
        }
        return boundFunc;
      }
      var obj = {
      }
      function createAgumon(gender, age) {
        this.name = "agumon";
        this.gender = gender;
        this.age = age;
      }
      createAgumon.prototype.college = 'THU'
      var createAgumonBind = createAgumon.Zbind(obj, 'female');
      var newObj = new createAgumonBind(22);
      console.log(newObj.college)// undefined
复制代码

可以看出来原型链丢失了,newObj.college得是'THU'才行

修改:

Function.prototype.Zbind = function (othis) {
        var originFunc = this;
        var partArgs = [].slice.call(arguments, 1);
        var func = function() {};
        var boundFunc = function () {
          var finalArgs = partArgs.concat([].slice.call(arguments));
          return originFunc.apply(this instanceof boundFunc ? this : othis, finalArgs);
        }
        func.prototype = originFunc.prototype;
        boundFunc.prototype = new func();
        return boundFunc;
      }
      var obj = {
      }
      function createAgumon(gender, age) {
        this.name = "agumon";
        this.gender = gender;
        this.age = age;
      }
      createAgumon.prototype.college = 'THU'
      var createAgumonBind = createAgumon.Zbind(obj, 'female');
      var newObj = new createAgumonBind(22);
      console.log(newObj.college)// 'THU'
复制代码

为什么要使用func.prototype = originFunc.prototype;boundFunc.prototype = new func();,而不是直接用**boundFunc.prototype = originFunc.prototype;**是因为这样写的话,修改boundFunc.prototype会影响到原函数的prototype。

that'all


参考资料:

mdn-bind

javascript中,new操作符的工作原理是什么?




相关文章
解决 ERROR: cannot launch node of type [xxx]: can‘t locate node [xxx] in package [xxx]
解决 ERROR: cannot launch node of type [xxx]: can‘t locate node [xxx] in package [xxx]
911 0
|
XML 数据格式
警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property ‘source‘ to ‘org.eclips
警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property ‘source‘ to ‘org.eclips
116 0
警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property ‘source‘ to ‘org.eclips
对‘avformat_find_stream_info’未定义的引用、to the PKG_CONFIG_PATH environment variable
对‘avformat_find_stream_info’未定义的引用、to the PKG_CONFIG_PATH environment variable
94 0
解决报错信息 —— Error: Cannot find module ‘webpack-cli/bin/config-yargs’
解决报错信息 —— Error: Cannot find module ‘webpack-cli/bin/config-yargs’
391 0
|
JavaScript 前端开发
【build your own xxx】实现你自己的call和apply
【build your own xxx】实现你自己的call和apply
【build your own xxx】实现你自己的call和apply
|
SQL Java 数据库连接
Could not find resource xxx/xxxx/xxx.xml报错解决
Could not find resource xxx/xxxx/xxx.xml报错解决
Could not find resource xxx/xxxx/xxx.xml报错解决
Unable to resolve dependency for ‘xxx项目@debug/compileClasspath‘: Could not resolve com.jakew
Unable to resolve dependency for ‘xxx项目@debug/compileClasspath‘: Could not resolve com.jakew
Unable to resolve dependency for ‘xxx项目@debug/compileClasspath‘: Could not resolve com.jakew
打包运行报no main manifest attribute, in XXXX的解决办法
打包运行报no main manifest attribute, in XXXX的解决办法
ES6—27:call_apply_bind方法总结
ES6—27:call_apply_bind方法总结
142 0
ES6—27:call_apply_bind方法总结