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 fBound === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fBound
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// 这里需要判断是否存在prototype属性 应为Funtion.prototype 是不存在prototype属性的
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
}
这个方法的主要几个难点 在于 第一判断是否是使用构造函数(new xx()) 还有就是原型链的关联。
这两点不容易理解
首先 我们创建的fBound这个函数是用作最后返回的,我们传递了一个 需要绑定的oThis 进来 需要做的就是把他绑定到我们需要绑定的函数上。所以最终返回的肯定是一个 绑定好后的函数。我们先拿到调用这个函数的函数 fToBind 。
我们用this instanceof fBound 这里就是用来判断 我们返回出去的这个函数到底是 一个普通的函数 还是一个 构造函数 ,因为当我们用 new 去创建一个对象的时候 这个 函数的 this 会指向本身 比如:
function Fun(){
console.log(this)
}
new Fun();
// Fun();
所以 this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用。如果这个时候我们还是使用传进来的oThis的话 会出现 构造函数绑定到 oThis 上 这不是我们要的结果。必须要判断。如果只想oThis 那么 你的构造函数里面的用 this声明的属性就会出问题。
还有一个 就是原型的关联问题,这里要做一个严谨的判断 因为 Function 和 Function.prototype typeof 都是 ‘function’ 类型的。但是 function.prototype 没有prototype属性。
剩下的就是正常的原型关联。这个方法相对来说是 比较严谨的。可以理解下来 之后 面试可能用的到