众所周知,bind、call、apply都是用来改变this指向的,其中bind是返回一个函数,你需要再次手动调用。
举例:
var obj = {
a: 1,
func: function() {
console.log(this.a)
}
}
// 需要在最后加个括号手动执行func方法
obj.func.bind({a:2})() // 2
实现方式很简单:
Function.prototype.bind = function(context){
// 取出bind方法中传入的除第一个参数(第一个参数是需要绑定的this)外的其余参数存在args数组中
var args = Array.prototype.slice.call(arguments, 1),
// 这里的this是指调用bind方法的函数
self = this;
return function(){
// 获取执行bind函数传入的参数
var innerArgs = Array.prototype.slice.call(arguments);
// 将第二个括号中的参数concat进args得到除第一个参数外所有传入的参数(这里有两个知识点:1、因为闭包args参数的值一直存在在内存中;2、偏函数(和函数柯里化相似但有点不同))
var finalArgs = args.concat(innerArgs);
// 调用apply方法,return函数结果
return self.apply(context,finalArgs);
};
};
想必上面的实现代码大家都能看懂,我们再看一个构造函数调用bind后执行的结果:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return this.x + ',' + this.y;
};
var YAxisPoint = Point.bind(null, 0); // 第1行
var axisPoint = new YAxisPoint(5); // 第2行
axisPoint.toString(); // '0,5' 第3行
axisPoint instanceof Point; // true 第4行
axisPoint instanceof YAxisPoint; // true 第5行
new Point(17, 42) instanceof YAxisPoint; // true 第6行
其中,第5行代码不难理解,因为axisPoint是YAxisPoint new出来的对象,理所当然是YAxisPoint的实例。
但是第4行axisPoint也是Point的实例,那就说明YAxisPoint的原型和Point的原型是继承关系或者说他们的原型指向同一个原型。
再看第6行,Point的实例指向YAxisPoint(即第4行和第6行有点相互牵制的意思),所以说明YAxisPoint的原型和Point的原型指向同一个原型,因为如果是继承关系的话,第4行和第6行总有一个会是false。
最终实现:
Function.prototype.bind = function (context) {
// 如果调用bind的不是一个function类型,直接报错,不再向下执行
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var args = Array.prototype.slice.call(arguments, 1),
self = this,
bound = function () {
// 这里和上面一版实现不同的是,apply的this指向做了一点改动,如果是构造函数调用,那么apply传入的第一个参数会被忽略,其余参数仍然可用(这里为什么这么写,其实没有太明白)
return self.apply(
this instanceof self ? this : context || window,
args.concat(Array.prototype.slice.call(arguments))
);
};
// 针对bind调用的函数是构造函数的场景,通过上面分析,调用bind的构造函数的原型和bind返回的函数的原型指向同一个原型,即将this.prototype赋值给bound.prototype
bound.prototype = this.prototype;
return bound;
};
偏函数与柯里化区别:
柯里化是将一个多参数函数转换成多个单参数函数,也就是将一个 n 元函数转换成 n 个一元函数。
偏函数则是固定一个函数的一个或者多个参数,也就是将一个 n 元函数转换成一个 n - x 元函数。
n元就是n个参数
文章如有理解错误之处,不吝赐教~