apply 通过调用目标函数并传入指定的上下文对象来改变 this 指向,执行完毕后返回该函数的运行结果。具体做法是创建一个普通对象作为新上下文,将需要共享的属性挂载到该对象上,然后使用 function.prototype.apply 方法调用原函数并将该对象作为第一个参数传入。这样做可以让原函数在内部将 this 绑定到新对象,从而访问其属性或修改其状态。

如何手动实现 apply 的核心逻辑
要实现 apply 的效果,核心在于利用对象的隐式绑定特性。我们将目标函数设置为上下文对象的一个临时属性,然后通过该对象调用这个属性函数,此时函数内部的 this 就会指向该对象。处理完返回值后,删除该临时属性以恢复原状。这种方法模拟了引擎内部处理 this 绑定的基本机制。

function myApply(context, args) {
if (typeof context === 'undefined' || context === null) {
context = window;
} else {
context = Object(context);
}
const fnKey = Symbol('fn');
context[fnKey] = this;
let result;
if (args && args.length > 0) {
result = context[fnKey](...args);
} else {
result = context[fnKey]();
}
delete context[fnKey];
return result;
}
const obj = { name: 'Alice' };
function greet(greeting) {
console.log(this.name + ': ' + greeting);
return 'done';
}
myApply.call(greet, obj, ['Hello']); // Alice: Hello
apply 与 call 在参数传递上的区别
apply 与 call 的主要区别在于接收参数的形式。call 要求将参数逐个列出,而 apply 接受一个数组(或类数组对象)作为第二个参数,会将该数组展开后依次传给目标函数。这种差异使得 apply 在处理未知长度参数列表或需要将数组直接传递给函数时更为方便。

const numbers = [5, 6, 7, 8]; // 使用 apply 展开数组求最大值 const maxNum = Math.max.apply(null, numbers); console.log(maxNum); // 8 // 使用 call 需要逐个传入参数 const maxNumCall = Math.max.call(null, 5, 6, 7, 8); console.log(maxNumCall); // 8 // 如果尝试用 call 传入数组,它会把整个数组当作第一个参数 const wrongMax = Math.max.call(null, numbers); console.log(wrongMax); // NaN
当传入的参数为 null 或 undefined 时 this 指向哪里
当 apply 的第一个参数为 null 或 undefined 时,在非严格模式下,this 会指向全局对象(浏览器中为 window)。这是因为引擎内部会先将 null 或 undefined 转换为全局对象,然后再进行属性查找和函数调用。在严格模式下,这种行为保持不变,但函数内部无法访问非严格模式下的某些全局变量特性,且 this 依然会被强制绑定到全局对象。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











