bind功能特性
- bind方法创建一个新函数,改变函数的作用域,并且不同于call、apply,函数不执行
- bind可用于实现偏函数,则实现时需要同时保存bind()被传入的参数arguments以及返回的新创建函数被传入的参数arguments
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
3.bind用于构造函数时候this作用域改变无效,核心点是在继承原函数的原形__proto__的时候增加一个fNOP父类,即 原型链继承方式 来判断原函数是否是new的构造函数,只有构造函数返回的对象才可以继承原型链
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return this.x + ',' + this.y;
};
var p = new Point(1, 2);
p.toString(); // '1,2'
var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// 以下这行代码在 polyfill 不支持,
// 在原生的bind方法运行没问题:
//(译注:polyfill的bind方法如果加上把bind的第一个参数,即新绑定的this执行Object()来包装为对象,Object(null)则是{},那么也可以支持)
var YAxisPoint = Point.bind(null, 0/*x*/);
var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'
axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true
原理
- 使用Array.prototype.slice.call()方法获取bind函数的arguments
- 使用Array.prototype.concat方法连接bind以及新函数的arguments以获得所有的arguments
- 使用原型链方法判断原this是否是new构造函数所得到的对象
代码实现
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {//如果原函数不是function类型,抛出类型错误
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),//获得bind方法的参数
fToBind = this, //保存调用函数
fNOP = function() {},//用来充当fBound的父类
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;
};
}
|