手写apply的核心是用function构造器动态生成call调用:将参数数组转为“argsarray[0],argsarray[1]”字符串,再执行fn.call(thisarg,...);需处理this绑定、空/非法参数等边界情况。

手写 apply 的核心在于:把传入的数组参数“展开”并作为实参调用目标函数,同时正确绑定 this。关键不是手动遍历拼接,而是利用 eval 或更安全的 Function 构造器 + 字符串拼接,但现代最佳实践是借助 call 和扩展运算符(若环境支持)——不过既然是手写、模拟原生行为,需兼容老环境,所以得用动态参数列表构造方式。
用 Function 构造器动态生成调用语句
这是最通用、不依赖扩展运算符的方法,适用于所有 ES5+ 环境:
- 把数组参数转为形如
"arg0, arg1, arg2"的字符串 - 用
Function构造器创建一个匿名函数,内部用fn.call(thisArg, ...)形式调用 - 注意:必须显式传入
thisArg和每个数组元素,不能直接写fn.apply(...)(否则就递归了)
示例实现:
Function.prototype.myApply = function(thisArg, argsArray) {
if (typeof this !== 'function') throw new TypeError('not a function');
thisArg = thisArg !== null && thisArg !== undefined ? thisArg : window;
if (!Array.isArray(argsArray) && argsArray !== null && argsArray !== undefined) {
throw new TypeError('CreateListFromArrayLike called on non-object');
}
if (!argsArray || argsArray.length === 0) {
return this.call(thisArg);
}
// 将 argsArray 转为参数字符串:"a,b,c"
const argsStr = argsArray.map((_, i) => `argsArray[${i}]`).join(',');
// 动态构造函数:返回 fn.call(thisArg, arg0, arg1, ...)
return new Function('fn', 'thisArg', 'argsArray', `return fn.call(thisArg, ${argsStr});`)
(this, thisArg, argsArray);
};
用 arguments + eval(不推荐,仅作理解)
eval 虽能拼接执行,但有安全与性能问题,且严格模式下禁用,仅用于说明原理:
- 将参数数组映射为变量引用字符串,如
"argsArray[0], argsArray[1]" - 拼成
"fn.call(thisArg, ...)"字符串后eval执行 - 实际项目中应避免,面试时可提一句“存在风险,生产环境不用”
ES6+ 环境下的简洁写法(非模拟,仅对比)
如果只是实现功能而非严格模拟原生(比如不考虑 IE8),可用扩展运算符:
Function.prototype.myApply = function(thisArg, argsArray) {
if (typeof this !== 'function') throw new TypeError('not a function');
thisArg = thisArg ?? window;
return this.call(thisArg, ...(Array.isArray(argsArray) ? argsArray : []));
};
但注意:这依赖 ...,本质是语法糖,不是“动态处理数组参数列表”的底层机制;手写 apply 的重点恰恰是绕过该语法,在无扩展运算符时还原其行为。
边界情况必须处理
原生 apply 对空数组、null/undefined、类数组、非数组对象都有明确规范:
-
argsArray为null或undefined→ 视为无参数(即调用fn.call(thisArg)) - 非数组且非 null/undefined → 抛
TypeError(V8 中报 “CreateListFromArrayLike called on non-object”) - 类数组对象(如
{0:1, 1:2, length:2})→ 原生apply会按length取索引属性,但手写时通常只处理真数组;若要完全兼容,需用Array.from或手动循环取[0]到[length-1]
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











