JavaScript bind() 方法的实现
bind() 方法的特点
-
bind() 方法会创建一个新函数。 当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this, 可以把除了第一个参数以外的其他参数都传递给下层的函数(这种技术称为“部分应用”,是“柯里化”的一种)注① 如果 bind() 返回的函数 作为构造函数使用,bind 时指定的 this 值会失效,但传入的参数有效。 new 调用返回的实例能够继承 绑定函数的原型 中的值
注①:
-
来自《你不知道的JavaScript》 关于局部应用与柯里化,引用 mqyqingfeng: 柯里化是将一个多参数函数转换成多个单参数函数,也就是将一个 n 元函数转换成 n 个一元函数。 局部应用则是固定一个函数的一个或者多个参数,也就是将一个 n 元函数转换成一个 n - x 元函数。 如果说两者有什么关系的话,引用 functional-programming-jargon 中的描述就是:Curried functions are automatically partially applied.
bind() 实现
方法一
Function.prototype.fakeBind = function(context) { if (typeof this !== "function") { throw new Error("Bind must be called on a function"); } let self = this; // 获得第一个参数以外的其他参数 let args = Array.prototype.slice.call(arguments, 1); let inner = function() { // 获得返回函数执行时被传入的参数 let innerArgs = Array.prototype.slice.call(arguments); // 1 new 情况下,this 指向实例。此时 bind 时指定的 this 值应予以失效; // 2 实例 instanceof 构造函数 返回值 true、false,确定是否为 new 调用; // 3 匿名函数直接调用 this 指向全局对象。此时应予以修改 this 的绑定 return self.apply( this instanceof inner ? this : context, args.concat(innerArgs) ); }; // inner.prototype = this.prototype // 按上面这么写的话,修改 返回函数原型对象(inner.prototype)的同时把 绑定函数的原型对象(this.prototype)也同时修改了。 // 用匿名函数做中转,this.protptype 就安全了。画个原型链的图就清楚了。 //注② let fNOP = function() { }; fNOP.prototype = this.prototype; inner.prototype = new fNOP(); return inner; };
注②
fNOP.prototype = this.prototype; 就是将 this.prototype 原型对象作为 fNOP.prototype 的原型对象,也就是 this.prototype 和 fNOP.prototype 指向同一个对象。 像 var f = new fNOP(); 之后找原型链上的属性,就是通过 f.proto, 因为 f.proto == fNOP.prototype == this.prototype 就会去 this.prototype 上找属性了。
方法二 ES6版
Function.prototype.fakeBindES6 = function(context, ...rest) { if (typeof this !== "function") { throw new Error("Bind must be called on a function"); } var self = this; return function inner(...args) { if (this instanceof inner) { // 当返回的内层函数作为构造函数使用,bind 时绑定的 this 失效。 // 即此处直接执行绑定函数,而不使用 apply 对 this 进行绑定 return new self(...rest, ...args); } // 当作为普通函数调用,this 指向传入的对象 return self.apply(context, rest.concat(args)); }; };
参考:
上一篇:
Java基础知识总结(2021版)
下一篇:
js面试题:引用类型赋值地址