43

用call或bind实现bind()

 4 years ago
source link: https://www.tuicool.com/articles/fu2M3qf
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、bind方法

让我们看一下MDN上对bind方法的解释

    bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。

也就是说,bind()方法会:

  • 创建一个新的函数(这也是它和call、apply不同的点)
  • 创建的函数接收bind的第二个及以后的参数作为自己的参数

那bind创建的这个新函数还有其他什么特性吗?

调用绑定函数时作为 this 参数传递给目标函数的值。 如果使用 new 运算符构造绑定函数,则忽略该值。

举个下面的例子:由bind创建的新函数bindFoo作为构造函数时,其创建的实例newBindFoo并不指向bindFoo绑定的obj,而是指向bindFoo。

var obj={
    name:"Melody"
}
var name="huyang"
function foo(tel){
    console.log(this.name)
    console.log(tel)
}
var bindFoo=foo.bind(obj,"110")

bindFoo()
//Melody
//110

var newbindFoo=new bindFoo();
//undefinde
//110

二、现在可以尝试用call实现bind啦

先实现前两个特性,用call模拟bind绑定this,并且对arguments进行分割处理实现其余参数传递

Function.prototype.bind2 = function (context) {
    	var self = this;
    	var args=Array.prototype.slice.call(arguments,1)//模拟bind时的传参
    	return function () {
    		var bindArgs=Array.prototype.slice(arguments)//模拟执行bind的返回函数时的传参
        	self.apply(context,args.concat(bindArgs));//修改返回函数的this指向为context,并将bind时和执行bind的返回函数传入的参数concat后绑定给返回函数。
    	}
}

修改返回函数的作用域链,使其指向绑定函数,这样返回函数生成的实例就可以继承绑定函数的原型啦。

Function.prototype.bind2 = function (context) {
    	var self = this;
    	var args=Array.prototype.slice.call(arguments,1)//模拟bind时的传参
    	var foo=function() {
    		var bindArgs=Array.prototype.slice(arguments)//模拟执行bind的返回函数时的传参
        	self.apply(this instanceof self ? this : context, args.concat(bindArgs));
                // 由于下方修改返回函数的prototype为绑定函数的prototype,当返回函数作为构造函数使用时,实例this instanceof self必定为真(instanceof判断的底层原理实际上就是根据原型链判断的)
                // 当作为普通函数时,this 指向 window,self 指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context
    
    	}
        foo.prototype=this.prototype
        return foo
}

需要注意的点:

arguments只是具有length属性且可以通过index读取的类数组对象,并没有slice等数组方法,要想对arguments使用数组方法必须得将arguments转换为真正的数组。故,使用Array.prototype.slice.call(arguments),对Array原型链中的slice方法调用call(或apply),传入arguments作为其上下文,然后返回arguments转换后的数组。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK