bind 和 call/apply 一样,都是用来改变上下文 this 指向的,不同的是,call/apply 是直接使用在函数上,而 bind 绑定 this 后返回一个函数(闭包) call和apply的唯一区别是call的除了第一个参数是绑定上下文,可以传多个参数,apply的第一个参数是绑定上下文,第二个参数是一个数组 call
Function.prototype.myCall = function(context) {
// 处理第一个参数传null或者undfined,这时将上下文绑定到window对象上
context = context || window;
context._fn = this;
let args = [...arguments].slice(1);
let result = context._fn(...args);
delete context._fn;
return result;
}
apply
Function.prototype.myApply = function(context) {
context = context || window;
context._fn = this;
let args = [...arguments].slice(1); // 第二个参数是数组
let result = context._fn(...args);
delete context._fn;
return result;
}
bind
- 函数调用,改变this
- 返回一个绑定this的函数
- 接收多个参数
- 支持柯里化形式传参 fn(1)(2)
Function.prototype.myBind = function(context) {
let self = this;
let args = [...arguments].slice(1);
return function() {
let newArgs = [...arguments];
return self.apply(context, args.concat(newArgs))
}
}
但是作为构造函数试用的时候会出错,构造函数的this绑定在实例上,除此之外,还需要解决原型丢失的问题
Function.prototype.myBind = function(context) {
let self = this;
let args = [...arguments].slice(1);
var bound = function() {
let newArgs = [...arguments];
// 作为构造函数使用
if(this instanceof bound) {
return self.apply(this, args.concat(newArgs))
} else {
return self.apply(context, args.concat(newArgs))
}
}
// 维护原型关系
if(this.prototype) {
bound.prototype = this.prototype;
}
return bound;
}