众所周知,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; };
参考文章:
https://www.cnblogs.com/heshan1992/p/6667596.html
偏函数与柯里化区别:
柯里化是将一个多参数函数转换成多个单参数函数,也就是将一个 n 元函数转换成 n 个一元函数。
偏函数则是固定一个函数的一个或者多个参数,也就是将一个 n 元函数转换成一个 n - x 元函数。
n元就是n个参数
文章如有理解错误之处,不吝赐教~