前置知识:原型链、new 的原理、call 或 apply 的使用
简单版:
// 1. 不要覆盖原有的 bind 方法,否则会造成意想不到的问题
Function.prototype.myBind = function (obj, ...rest) {
if (typeof this !== 'function') {
throw new Error('请使用一个函数调用 bind')
}
const selfFn = this
// 2. 如此简单的处理会使得 返回函数 作为 构造函数 时失效
return function (...args) {
selfFn.apply(obj, [...rest, ...args])
}
}
-
不要试图修改不属于自己的对象的某一个属性,不要覆盖任何不属于自己创造的属性
node 环境中出现的问题,如果使用
bind,而不是myBind,我们在函数实现内部添加一个console.log,就会导致爆栈,我猜测console.log的内部实现调用了bind方法,导致console.log的内部也会进行打印,并且上下文调用栈被不停的塞入上下文(该问题出现在 node 环境下,版本为:14.20.0;谷歌浏览器不会出现这个问题)。 -
当 bind 好的返回函数作为构造函数时,原始函数的原型链必须链接到新创建的对象,而不是原
bind的目标,符合new的要求(new绑定this的优先级高于硬绑定)
完整版:
Function.prototype.myBind = function (obj, ...rest) {
if (typeof this !== "function") {
throw new Error("请使用一个函数调用 bind");
}
const self = this
function fnBound (...args) {
// 此 this !== self,而是 fnBound 作为构造函数新创建的对象
const _this = this instanceof self ? this : obj
self.apply(_this, [...rest, ...args])
}
// 关于此处,我会补充另一种官方推荐的写法
fnBound.prototype.__proto__ = self.prototype
return fnBound
}
todo 补充概念:
new的原理bind作为构造函数时与原型链的纠葛
以上两个问题会更新的。