bind函数
bind(function, object, *arguments)
:绑定函数 function 到对象 object 上, 也就是无论何时调用函数, 函数里的 this 都指向这个 object。
我们先看上面的参考博文的实现,其中有几个要点:
-
bind
的基本实现(用闭包保存bind
传进来的上下文) -
bind
是可以传部分或者全部参数的 -
bind
后的函数是依旧可以当做构造函数来使用并且忽略bind
提供的this
的
再结合《你不知道的JavaScript(上)》里的bind
,我们可以得到这样一个bind
Function.prototype.myBind = function (context) {
context = Object(context) || window;
var self = this;
var args = [].slice.call(arguments, 1);
var constructor = function () {
args = args.concat([].slice.call(arguments));
if (this instanceof self) {
// 说明正在使用new
return self.apply(this, args);
} else {
// 普通的bind使用方法
return self.apply(context, args);
}
}
constructor.prototype = Object.create(self.prototype);
return constructor;
}
然后我们来看看underscore
中的_.bind
_.bind = function (func, context) {
// nativeBind
if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
// 上下文校验
if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
// 保存部分参数
var args = slice.call(arguments, 2);
var bound = function () {
return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
};
return bound;
};
我们也看到bind
函数实现的核心是executeBound
函数,它有5个参数
-
func
:bind
的目标函数 -
bound
:bind
的返回函数 -
context
:绑定上下文 -
this
:执行上下文 -
args
:执行参数
明白了参数的意义,我们再来看executeBound
的实现
var executeBound = function (sourceFunc, boundFunc, context, callingContext, args) {
if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
var self = baseCreate(sourceFunc.prototype);
var result = sourceFunc.apply(self, args);
if (_.isObject(result)) return result;
return self;
};
其实思路就跟之前的bind
函数是一样的了。
- 判断执行上下文是否是
new
赋值的新this
- 如果不是,当做普通的
bind
返回函数 - 如果是,则需要当做构造函数使用,就需要添加
prototype
和检验返回结果 -
baseCreate
添加原型,result
检验构造函数是否有返回值; - 如果这个返回值是对象,就返回这个对象;否则返回
构造函数
执行的结果。
于是发现,Underscore
源码实现的bind
函数,跟我们之前实现的是一样的。