bind函数的主要目的,是改变函数执行时this的指向,也就是函数执行环境的上下文。
小插曲:什么是方法?当对象的属性是一个函数时,我们称之为对象的一个方法。为什么修改this指向?因为方法内部的函数,this默认会指向全局window,为什么会这样呢?因为语言缺陷!还有,原型prototype是一个对象,一个对象,对象,象…想起了曾经写过的
B = function(){...};
//无知者无畏啊!
a.prototype = B;//错
a.prototype = new B();//对
简单修改函数this指向,我们可以像下面一样给目标函数绑定作用域:
Function.prototype.bind = function(context){
//将调用bind的目标函数的this保存起来
var self = this;
return function(){
return self.apply(context,arguments);
}
}
考虑到函数柯里化,支持bind在绑定对象时传递参数:
Function.prototype.bind = function(context){
//将调用bind的目标函数的this保存起来
var self = this,
args = Array.prototype.slice.call(arguments,1);//eg:foo.bind(obj,1)
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return self.apply(context,finalArgs);
}
}
现在实现了this指向的绑定,我们需要做的是让返回的函数能够继承self原有的属性,即原型链的继承:
Function.prototype.bind = function(context) {
//将调用bind的目标函数的this保存起来
var self = this,
FNop = function() {},
args = Array.prototype.slice.call(arguments, 1), //eg:foo.bind(obj,1)
bound = function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return self.apply(context, finalArgs);
};
//使用空转函数FNop继承self的原型对象,再将返回函数的原型作为空转函数的实例,这样在修改bound.prototype属性时就不会更改self.prototype属性了,这也是不使用bound.prototype = self.prototype的意义所在
FNop.prototype = self.prototype;
bound.prototype = new FNop();
return bound;
}
最后为了浏览器能够支持bind,毕竟bind是ES5才有的prototype方法,我们只需要小小修改即可,主要是对调用bind的目标不是函数是作出提示,这也是原生JS实现bind的方法:
Function.prototype.bind = function(context) {
//判断调用bind的目标是否为函数
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
//将调用bind的目标函数的this保存起来
var self = this,
FNop = function() {},
args = Array.prototype.slice.call(arguments, 1), //eg:foo.bind(obj,1)
bound = function() {
return self.apply(this instanceof FNOP && context ? this : context || window,
args.concat(Array.prototype.slice.call(arguments)));
};
//使用空转函数FNop继承self的原型,再将返回函数的原型作为空转函数的实例,这样在修改bound.prototype属性时就不会更改self.prototype属性了,这也是不使用bound.prototype = self.prototype的意义所在
FNop.prototype = self.prototype;
bound.prototype = new FNop();
return bound;
}