手写bind()
描述:
bind()和apply还有call都可以改变关键词this的作用域,它们的用法有所不同,各有千秋,以下是对三个函数的描述和使用例子:
-
apply:func.apply(obj,[arg1,arg2,...]) 把函数func内部的this作用域指向obj,然后把传给func的参数分别放到数组中传给func
-
call:func.call(obj,arg1,arg2,...) 与apply类似,不过传参的方式是一个一个传,不用放在数组里边
-
bind:func.bind(obj,arg1,arg2,...)(other-arg); 与call和apply不同的是,bind()可以预定义参数,arg1和arg2为预定义的参数,other-arg为其他参数,这么做的好处在于,我们可以用先用一个变量var vary = func.bind(obj,arg1,arg2,...),然后再使用vary(other-arg)来传入其他参数,如此一来,就相当于给函数预先传入了一些相对不变参数,一些需要变化的参数再另外传入,这是apply和call都做不到的。
bind的用法举例及其效果
手写bind代码部分:
// 定义在Function.prototype上,好让使用Function构造器创建新函数的时候都自带bind()方法
Function.prototype.bind=function(obj,arg){
// 获取从第二个参数起也就是除了obj之外的其余参数
var arg=Array.prototype.slice.call(arguments,1);
// 把this作用域赋给context,因为关键词this的作用域在不同的地方不一样
var context=this;
// 定义一个函数,使之可以拼接原bind函数传入的参数,即bind(obj,args1)(args2) == bind(obj,args1,args2)
// 这里默认让newArg为一个对象,不然会报错
var bound=function(newArg={}){
arg=arg.concat(Array.prototype.slice.call(newArg));
return context.apply(obj,arg);
}
// 接下来就是创建一个新函数,使它的prototype(原型对象)等于Function的prototype,然后再把要return的函数bound的prototype指向F这个构造函数,
// 就把bind()方法放到Function.prototype中去了
var F=function(){}
F.prototype=context.prototype;
bound.prototype=new F();
return bound;
}
附一张原型链图方便大家理解:
参考文章(对原型链的理解):
https://www.jianshu.com/p/423f72d502c2 还不懂原型链的建议看看