严格模式下替换arguments.callee的兼容方案(支持至ES2019)
严格模式兼容重构方案
原代码依赖严格模式下被完全禁用的非标准API:arguments.callee、Function.caller,在开启'use strict'时会直接抛出TypeError。以下是兼容到ES2019的重构实现,完全对齐原有函数的行为,不依赖任何被禁用的特性。
核心实现思路:通过Error实例的栈追溯能力获取完整调用链,解析栈字符串提取对应层级的函数名,所有支持ES2019的运行环境(现代浏览器、Node.js 12+)均原生支持该特性。
重构后完整代码
'use strict'; const utils = { /** * 获取上两层调用方的函数名 * @param {string} [string] 原接口遗留参数,无实际逻辑作用,仅做兼容 * @param {string} [callerName] 原接口遗留参数,无实际逻辑作用,仅做兼容 * @return {string} */ caller: function (string, callerName) { const stackFrames = this._getStackFrames(); // 栈帧偏移:0为内部栈解析方法、1为当前caller方法、2为直接调用方、3为目标上两层调用方 const targetFrame = stackFrames[3]; return targetFrame ? this._extractFunctionName(targetFrame) : ''; }, /** * 获取直接调用方的函数名 * @return {string} */ function_name: function () { const stackFrames = this._getStackFrames(); // 栈帧偏移:0为内部栈解析方法、1为当前function_name方法、2为目标直接调用方 const targetFrame = stackFrames[2]; return targetFrame ? this._extractFunctionName(targetFrame) : ''; }, /** * 内部方法:获取当前调用栈帧列表 * @returns {string[]} * @private */ _getStackFrames: function () { const err = new Error(); // 统一换行符拆分栈行,过滤错误首行和空行 return err.stack .split(/\r?\n/) .filter(line => { const trimmed = line.trim(); return trimmed.length > 0 && !trimmed.startsWith('Error'); }); }, /** * 内部方法:从栈帧行提取函数名 * @param {string} frameLine * @returns {string} * @private */ _extractFunctionName: function (frameLine) { const trimmedLine = frameLine.trim(); // 匹配标准栈格式:at 函数名 (位置信息) const namedFnMatch = trimmedLine.match(/^at\s+([^\s(]+)\s*\(/); if (namedFnMatch?.[1] && namedFnMatch[1] !== '<anonymous>') { return namedFnMatch[1]; } // 匹配全局/顶层调用的无括号格式 const globalMatch = trimmedLine.match(/^at\s+([^:\\/]+):\d+:\d+$/); if (globalMatch?.[1]) { return globalMatch[1]; } return ''; } };
使用注意事项
- 实现完全对齐原有逻辑行为:匿名函数、无名称绑定的箭头函数会返回空字符串,和旧代码表现一致
- 内部辅助方法不要改写为箭头函数,否则会导致栈帧偏移计算错误
- 代码经过压缩混淆时函数名会被编译工具替换为短标识,该表现和旧实现完全一致,属于编译阶段的正常现象
- 兼容所有ES2019标准运行环境,严格模式下无任何报错
内容的提问来源于stack exchange,提问作者German_Detlev
相关产品推荐
相关产品推荐

