核心特性对比
| 方法 | 执行时机 | 参数形式 | 返回值类型 |
call | 立即执行 | 逗号分隔参数 | 原函数结果 |
apply | 立即执行 | 数组参数 | 原函数结果 |
bind | 延迟执行 | 逗号分隔参数 | 新函数对象 |
功能详解
call方法示例
function showInfo(title, symbol) {
return `${title}:${this.userName}${symbol}`;
}
const profile = { userName: '张三' };
const output = showInfo.call(profile, '姓名', '!');
console.log(output); // "姓名:张三!"
apply方法示例
function calculate(x, y, z) {
return this.base * (x + y + z);
}
const settings = { base: 5 };
const total = calculate.apply(settings, [2, 3, 4]);
console.log(total); // 45 (5*(2+3+4))
bind方法示例
function display(message, separator) {
return `${this.id}${separator}${message}`;
}
const item = { id: 'ID-100' };
const boundDisplay = display.bind(item, '已绑定');
console.log(boundDisplay(':')); // "ID-100:已绑定"
底层实现模拟
call方法实现
Function.prototype.customCall = function(ctx, ...params) {
ctx = ctx || globalThis;
const tempProp = Symbol('temp');
ctx[tempProp] = this;
const outcome = ctx[tempProp](...params);
delete ctx[tempProp];
return outcome;
};
// 验证
function add(a, b) {
console.log(this.prefix, a + b);
}
const env = { prefix: '结果:' };
add.customCall(env, 7, 8); // 输出: 结果: 15
apply方法实现
Function.prototype.customApply = function(ctx, argList = []) {
ctx = ctx || globalThis;
const uniqueKey = Symbol('key');
ctx[uniqueKey] = this;
const res = ctx[uniqueKey](...argList);
delete ctx[uniqueKey];
return res;
};
// 验证
function multiply(a, b) {
return this.factor * a * b;
}
const config = { factor: 3 };
console.log(multiply.customApply(config, [4, 5])); // 60
bind方法实现
Function.prototype.customBind = function(ctx, ...fixedArgs) {
const targetFunc = this;
return function(...dynamicArgs) {
const combined = fixedArgs.concat(dynamicArgs);
if (new.target) {
return new targetFunc(...combined);
}
return targetFunc.apply(ctx, combined);
};
};
// 验证
function User(name, role) {
this.name = name;
this.role = role;
}
const BoundUser = User.customBind(null, '王五');
const user = new BoundUser('管理员');
console.log(user); // { name: '王五', role: '管理员' }
典型应用场景
类数组转换
const pseudoArray = { 0: '一', 1: '二', length: 2 };
const actualArray = [].map.call(pseudoArray, item => item + '号');
console.log(actualArray); // ['一号', '二号']
参数预置
function power(a, b) {
return Math.pow(a, b);
}
const square = power.bind(null, 2);
console.log(square(5)); // 32 (2^5)
事件绑定
class Toggle {
constructor() {
this.state = '开启';
this.toggleHandler = this.toggleHandler.bind(this);
}
toggleHandler() {
console.log(`当前状态: ${this.state}`);
}
}
关键注意事项
- 严格模式下原始值参数不会自动装箱
- 频繁调用bind可能引发内存问题
- 箭头函数忽略上下文绑定操作
const arrowExample = () => console.log(this.env);
arrowExample.call({ env: '测试' }); // 输出全局this而非测试对象