怎么手写实现bind函数

本篇内容介绍了“怎么手写实现bind函数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

创新互联公司专注于企业成都营销网站建设、网站重做改版、八步网站定制设计、自适应品牌网站建设、HTML5商城网站制作、集团公司官网建设、成都外贸网站建设、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为八步等各大城市提供网站开发制作服务。

前面发了一篇文章,面试题目之原生实现call、apply、bind,这篇文章介绍了如何手动实现call、apply、bind,但是前不久重读这篇文章时发现了实现bind的代码不是很完善,我们看一段代码:

function Person(){  this.name="zs";  this.age=18;  this.gender="男"}var obj={  hobby:"看书"}//  将构造函数的this绑定为objvar changePerson = Person.bind(obj);//  直接调用构造函数,函数会操作obj对象,给其添加三个属性;changePerson();//  1、输出objconsole.log(obj);
//  用改变了this指向的构造函数,new一个实例出来var p = new changePerson();// 2、输出objconsole.log(p);

代码输出结果:

1、输出:

怎么手写实现bind函数

2、输出:

怎么手写实现bind函数

仔细观察上面的代码,再看输出结果。

我们对Person类使用了bind将其this指向obj,得到了changeperson函数,此处如果我们直接调用changeperson会改变obj,若用new调用changeperson会得到实例 p,并且其__proto__指向Person,我们发现bind失效了。

我们得到结论:用bind改变了this指向的函数,如果用new操作符来调用,bind将会失效。

再看我们这篇文章(面试题目之原生实现call、apply、bind)中bind实现的代码:


Function.prototype.myBind = function(ctx, ...argv1) {    return (...argv2) => {        return this.call(ctx, ...argv1, ...argv2)    }}

如果看不太习惯,将其转化为es5的执行方式:

Function.prototype.mybind = function(){  // 1、保存函数  var _this = this;  // 2、保存目标对象  var context = arguments[0]||window;  // 3、保存目标对象之外的参数,将其转化为数组;  var rest = Array.prototype.slice.call(arguments,1);  // 4、返回一个待执行的函数  return function F(){  // 5、将二次传递的参数转化为数组;    var rest2 = Array.prototype.slice.call(arguments)    //6、用apply调用第一步保存的函数,并绑定this,传递合并的参数数组    _this.apply(context,rest.concat(rest2));  }}

我们用自己实现的mybind函数,来实现文章最上面的例子,测试一下如果,用mybind函数改变了构造函数的this,然后用new来执行生成的新函数,能否得到和原生bind一样的效果,测试代码如下:

function Person(){  this.name="zs";  this.age=18;  this.gender="男"}var obj={  hobby:"看书"}//  将构造函数的this绑定为obj ,此处调用上面开发的mybind方法;var changePerson = Person.mybind(obj);//  直接调用构造函数,函数会操作obj对象,给其添加三个属性;changePerson();//  1、输出objconsole.log(obj);
//  用改变了this指向的构造函数,new一个实例出来var p = new changePerson();// 2、输出objconsole.log(p);

查看输出结果:

1、输出:

怎么手写实现bind函数

2、输出:

怎么手写实现bind函数

我们用上面实现的mybind改变函数的this,然后调用new方法,发现并未实现和原生bind一样的效果,我们实现的mybind方法和原生的bind实现的功能还有些差距,那么我们如何修正呢?

仔细观察代码,发现突破点再这里: new changeperson()。

这里我们只需要在调用 new changeperson()时候,判断一下,是否是通过new操作符调用的,如果是new 操作符调用的话,我们就用new直接调用未改变this之前的函数,并返回其结果。

那么如何判断是否是通过new操作符来调用一个函数呢?这里我们就要用到instanceof了,看看官方文档对其解释:


|instanceof运算符用于测试构造函数的prototype属性是否出现在对象的

原型链中的任何位置。

翻译成大白话,就是判断某个实例是否由某个类或者构造函数生成。

回归正文,我们知道,我们在用new操作符调用一个构造函数时,或者普通函数,都会在函数内部执行如下步骤:

1、生成一个空对象,

2、然后将this指向这个空对象,

3、最后将这个对象返回。

而这个对象就是这个构造函数的实例,那么只要在函数内部执行 this instanceof 构造函数 来判断其结果是否为true,就能判断函数是否是通过new操作符来调用了,若结果为true则是用new操作符调用的,代码修正如下:

Function.prototype.mybind = function(){  // 1、保存函数  var _this = this;  // 2、保存目标对象  var context = arguments[0]||window;  // 3、保存目标对象之外的参数,将其转化为数组;  var rest = Array.prototype.slice.call(arguments,1);  // 4、返回一个待执行的函数  return function F(){     // 5、将二次传递的参数转化为数组;     var rest2 = Array.prototype.slice.call(arguments)    if(this instanceof F){      // 6、若是用new操作符调用,则直接用new 调用原函数,并用扩展运算符传递参数      return new _this(...rest2)    }else{           //7、用apply调用第一步保存的函数,并绑定this,传递合并的参数数组      _this.apply(context,rest.concat(rest2));    }  }}

此时,测试在运行上面的测试案例,打印结果为:

怎么手写实现bind函数

完美实现了和原生bind一样的效果,对一个知识点进行比较深入的研究确实不容易,越深入发现涉及的知识越广泛,就像这篇文章,虽然说得是bind的手动实现,但是其实涉及了new操作符调用的原理,instanceof 的用法。

“怎么手写实现bind函数”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!


本文名称:怎么手写实现bind函数
浏览地址:http://myzitong.com/article/igjeij.html