您的位置:首页 > Web前端 > JavaScript

JavaScript bind() 方法的实现

2018-03-31 11:00 375 查看

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));
};
};


参考:https://github.com/mqyqingfeng/Blog/issues/12
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bind 前端面试