出处:掘金
原作者:金泽宸
call:立即执行 + 传参列表apply:立即执行 + 传参数组bind:返回一个新函数,不立即执行;绑定 this 和前几个参数this)this、本质执行流程、原型继承fn.call(obj, arg1, arg2)
// 等价于:
obj.fn = fn
obj.fn(arg1, arg2)
delete obj.fn
callFunction.prototype.myCall = function (context, ...args) {
// 1. 处理 context 的边界情况(null/undefined/原始值)
if (context === null || context === undefined) {
context = globalThis; // 非严格模式下,默认指向全局对象
} else if (typeof context !== 'object') {
context = new Object(context); // 原始值转换为包装对象(如数字 1 → Number 对象)
}
// 2. 用 Symbol 创建唯一属性,避免覆盖 context 原有属性
const uniqueThis = Symbol('unique');
context[uniqueThis] = this; // this 是当前函数
// 3. 调用函数,此时函数内部的 this 指向 context
const result = context[uniqueThis](...args);
// 4. 删除临时属性,避免污染 context
delete context[uniqueThis];
// 5. 返回函数执行结果
return result;
};
applyFunction.prototype.myApply = function (context, args) {
// 1. 处理 context 的边界情况(null/undefined/原始值)
if (context === null || context === undefined) {
context = globalThis; // 非严格模式下,默认指向全局对象
} else if (typeof context !== 'object') {
context = new Object(context); // 原始值转换为包装对象(如数字 1 → Number 对象)
}
// 2. 用 Symbol 创建唯一属性,避免覆盖 context 原有属性
const uniqueThis = Symbol('unique');
context[uniqueThis] = this; // this 是当前函数
// 3. 调用函数,此时函数内部的 this 指向 context
const result = Array.isArray(args)
? context[uniqueThis](...args)
: context[uniqueThis]();
// 4. 删除临时属性,避免污染 context
delete context[uniqueThis];
// 5. 返回函数执行结果
return result;
};
bindFunction.prototype.myBind = function (context, ...outArgs) {
// 1. 判断 context 类型
if (context === undefined || context === null) {
context = globalThis;
} else {
context = Object(context);
}
// 2.唯一属性保存
const uniquePrototype = Symbol("unique");
context[uniquePrototype] = this;
// 3.返回调用的函数
return function (...innerArgs) {
return context[uniquePrototype](...outArgs, ...innerArgs);
};
};
缺陷:
Symbol("unique"),不能删除,删除后返回的函数无法重复执行bind 不同,这个自定义的实现不支持通过 new 调用绑定函数以创建对象。如果尝试使用 new 来实例化绑定函数,会导致错误或意外的行为bind 函数绑定函数时,绑定函数和原函数之间共享原型。然而,这个自定义的实现并没有处理这种情况,导致原型继承相关的特性无法正确传递length 属性: 在 JavaScript 中,函数对象具有一个 length 属性,它返回函数定义的参数数量。使用原生的 bind 函数绑定后的函数会保留正确的 length 属性,但这个自定义实现并没有处理 length 属性,它会返回原始函数的参数数量,而不是绑定函数的参数数量bind 函数返回的绑定函数是可以取消绑定的(通过使用 Function.prototype.unbind 或 ES6 的 Function.prototype.@@unbound),但是这个自定义的实现并没有提供取消绑定的方法Function.prototype.myBind = function (context, ...outArgs) {
const self = this;
function boundFunction(...innerArgs) {
// 如果是用 new 调用
if (this instanceof boundFunction) {
return new self(...outArgs, ...innerArgs);
}
return self.apply(context, [...args, ...restArgs]);
}
// 原型继承
boundFunction.prototype = Object.create(this.prototype);
// 添加 unbind 方法,返回原始函数
boundFunction.unbind = () => self;
return boundFunction;
};
| 错误理解 | 正确做法 |
|---|---|
bind 会立即执行 |
❌,它返回一个函数,不会立即执行 |
没有处理 new 场景 |
✅ 用 this instanceof 区分 |
| 覆盖对象属性名 | ✅ 用 Symbol 解决 |