learn
learn copied to clipboard
JavaScript深入之bind的模拟实现
JavaScript深入之bind的模拟实现
基本实现
我们可以首先得出 bind 函数的两个特点:
- 返回一个函数
- 可以传入参数
如:
var foo = {
value: 1
};
function bar(name, age) {
console.log(this.value);
console.log(name);
console.log(age);
}
var bindFoo = bar.bind(foo, "yyy");
bindFoo("28");
第一步:返回一个函数
Function.prototype.mybind1 = function(context) {
const self = this;
return function() {
return self.apply(context);
};
};
第二步:可以传参,并且可以这样:函数需要传 name 和 age 两个参数,可以在 bind 的时候,只传一个 name,在执行返回的函数的时候,再传另一个参数 age!
Function.prototype.mybind2 = function(context) {
const self = this;
const args = Array.prototype.slice.call(arguments, 1);
return function() {
const bindArgs = Array.prototype.slice.call(arguments);
return self.apply(context, args.concat(bindArgs));
};
};
构造函数效果实现
完成了这两点,最难的部分到啦!因为 bind 还有一个特点,就是
一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
第三步:
Function.prototype.mybind3 = function(context) {
const self = this;
const args = Array.prototype.slice.call(arguments, 1);
// 通过一个空函数来进行中转
const fNOP = function() {};
const fBound = function() {
const bindArgs = Array.prototype.slice.call(arguments);
// this 指向 实例,说明是构造函数,需要将绑定函数的 this 指向该实例,
// 可以让实例获得来自绑定函数的值
// this 指向 window,说明使普通函数调用,将绑定函数的 this 指向 context
return self.apply(
this instanceof fNOP ? this : context,
args.concat(bindArgs)
);
};
fNOP.prototype = this.prototype;
// 让实例继承绑定函数的原型(this.prototype)中的值
fBound.prototype = new fNOP();
return fBound;
};
最终版
Function.prototype.mybind = function(context) {
if (typeof this !== "function") {
throw new Error(
"Function.prototype.bind - what is trying to be bound is not callable"
);
}
const self = this;
const args = Array.prototype.slice.call(arguments, 1);
const fNOP = function() {};
const fBound = function() {
const bindArgs = Array.prototype.slice.call(arguments);
return self.apply(
this instanceof fNOP ? this : context,
args.concat(bindArgs)
);
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};