代码语言:javascript复制
// bind会返回一个硬绑定的新函数,新函数会使用指定的第一个thisCtx去调用原始函数,并将其它参数传给原始函数。 硬绑定会降低函数的灵活性,在绑定之后不能通过显式或硬绑定的方式改变this,只能通过new改变
// softBind 会对指定的函数进行封装,首先检查调用时的 this,如果 this 绑定到全局对象或者 undefined,那就用指定的thisCtx 去调用函数,否则不会修改 this
Function.prototype.myBind = function (context, ...args) {
const self = this;
const fn = function (...newArgs) {
console.log("this", this); // 链式调用的时候 { a: 6 }
console.log("context", context); //{ a: 2 }
// 优先判断是否来自new 调用之后的实例,是的话 this 不变
self.apply(this instanceof fn ? this : context, args.concat(newArgs));
};
fn.prototype = Object.create(this.prototype);
return fn;
};
function f1(b) {
console.log(this.a, b);
}
let fb11 = f1.myBind({ a: 1 }, 10);
let bindFn1 = new fb11(); // undefined 10 因为 new 调用优先级高于 bind 改变的this 指向
let fb22 = f1.myBind({ a: 2 }, 10);
fb22(); // 2,10
let fb33 = f1.myBind({ a: 3 }, 10);
fb33(); // 3,10
let fb66 = fb22.myBind({ a: 6 }, 10)(); // 2,10
// fb66(); // 2,10
// 结论:bind方法链式调用,都以第一次bind绑定为准,所以叫硬绑定,原理为 下一次 调用bind的方法为上一个bind方法返回的闭包,已经将 context、args 存储好并固定返回了
// 参考链接:https://juejin.cn/post/6921897996258918413
// bind方法分别多次调用,各自都可绑定成功
console.log("=================");
// softBind globalThis 代表获取当前环境下的全局对象
Function.prototype.softBind = function (context = globalThis, ...args) {
const self = this;
const fn = function (...newArgs) {
// new 的时候和链式调用 softBind 的时候打印
if (this !== globalThis) {
console.log("this", this); // 链式调用的时候 { a: 6 }
console.log("context", context); //{ a: 2 }
}
self.apply(
this instanceof fn ? this : !this || this === globalThis ? context : this,
args
);
};
fn.prototype = Object.create(this.prototype);
return fn;
};
let fs22 = f1.softBind({ a: 2 }, 10);
fs22(); // 2 10
let fs33 = f1.softBind({ a: 3 }, 10);
fs33(); // 3 10
let fs66 = f1.softBind({ a: 2 }, 10).softBind({ a: 6 }, 10);
fs66(); //6 10
let fs11 = f1.softBind({ a: 1 }, 10);
let softbindFn1 = new fs11(); // undefined 10 因为 new 调用优先级高于 bind 改变的this 指向