bind官方定义:bind()方法创建一个新的函数, 当这个新函数被调用时其this置为提供的值,其参数列表前几项置为创建时指定的参数序列
apply官方定义:apply()
方法调用一个具有给定this
值的函数,以及作为一个数组(或类似数组对象)提供的参数
var obj = { x: 1 };
function add(y) {
alert(this.x);
alert(arguments);
}
add.apply(obj, [1, 2]);
var addbind = add.bind(obj, 1, 2);
addbind(3);
上面这段代码二者最终效果是等价的,区别就在于bind返回的是一个函数
按照bind的定义,我们要返回一个函数,这个函数只要调用add.apply(obj, [1, 2]);
就能达到我们的效果
Function.prototype.testBind = function() {
var fBound = function() {
return add.apply(obj, [1, 2]);
};
return fBound;
}
bind方法第一个入参是this值,我们修改函数传入this,也就是apply中的obj
Function.prototype.testBind = function(oThis) {
var fBound = function() {
return add.apply(oThis, [1, 2]); //obj替换为oThis
};
return fBound;
}
那么下一步我们要解决add替换的问题,在js中this永远指向最后调用它的对象add.bind(obj, 1, 2);
,那么bind的调用对象就是add,所以bind函数中的this也就是add这个调用对象
Function.prototype.testBind = function(oThis) {
var fToBind = this; //bind的调用对象add
var fBound = function() {
return fToBind.apply(oThis, [1, 2]); // add替换为fToBind
};
return fBound;
}
接下来解决arguments问题
Function.prototype.testBind = function(oThis) {
var fToBind = this; //bind的调用对象add
var aArgs = Array.prototype.slice.call(arguments, 1);
var fBound = function() {
var args = [...aArgs,...arguments]; // 拼接add函数参数
return fToBind.apply(oThis, args);
};
return fBound;
}
到此,一个简单的bind方法就实现了,但是bind方法远没有这么简单,还要处理原型链以及被用作构造函数的场景,官方实现:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
// this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fNOP
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
}