Function.prototype.caller
非标准:此特性未标准化。我们不建议在生产环境中使用非标准特性,因为它们浏览器支持有限,并且可能会更改或被移除。但是,在没有标准选项的特定情况下,它们可以是合适的替代方案。
已弃用:此特性不再推荐。虽然某些浏览器可能仍然支持它,但它可能已经从相关的网络标准中删除,可能正在删除过程中,或者可能仅为兼容性目的而保留。请避免使用它,如果可能,请更新现有代码;请参阅本页底部的兼容性表格以指导您的决策。请注意,此特性可能随时停止工作。
注意: 在 严格模式下,访问函数的 caller 会抛出错误 — 该 API 已被移除且没有替代方案。这是为了防止代码能够“遍历调用栈”,这既带来了安全风险,也严重限制了内联和尾调用优化等优化的可能性。有关更多解释,您可以阅读 arguments.callee 弃用的理由。
caller 属性是 Function 实例的一个访问器属性,它返回调用此函数的函数。对于 严格模式、箭头函数、异步函数和生成器函数,访问 caller 属性会抛出 TypeError。
描述
如果函数 f 是由顶层代码调用的,则 f.caller 的值为 null;否则,它就是调用 f 的函数。如果调用 f 的函数是严格模式函数,则 f.caller 的值也为 null。
请注意,ECMAScript 规范仅指定了一个行为,即 Function.prototype 具有一个初始的 caller 访问器,该访问器无条件地为任何 get 或 set 请求抛出 TypeError(称为“毒丸访问器”),并且不允许实现更改此语义,除非是非严格模式的普通函数,在这种情况下,它不能具有严格模式函数的值。caller 属性的实际行为,如果不是抛出错误,则由实现定义。例如,Chrome 将其定义为自己的数据属性,而 Firefox 和 Safari 则扩展了初始的“毒丸”Function.prototype.caller 访问器,以特殊处理非严格函数作为 this 值的情况。
(function f() {
if (Object.hasOwn(f, "caller")) {
console.log(
"caller is an own property with descriptor",
Object.getOwnPropertyDescriptor(f, "caller"),
);
} else {
console.log(
"f doesn't have an own property named caller. Trying to get f.[[Prototype]].caller",
);
console.log(
Object.getOwnPropertyDescriptor(
Object.getPrototypeOf(f),
"caller",
).get.call(f),
);
}
})();
// In Chrome:
// caller is an own property with descriptor {value: null, writable: false, enumerable: false, configurable: false}
// In Firefox:
// f doesn't have an own property named caller. Trying to get f.[[Prototype]].caller
// null
此属性取代了已废弃的 arguments 对象的 arguments.caller 属性。
特殊的 __caller__ 属性,它返回调用者的激活对象,从而允许重建调用栈,由于安全原因已被移除。
示例
检查函数 caller 属性的值
以下代码检查函数 caller 属性的值。
function myFunc() {
if (myFunc.caller === null) {
return "The function was called from the top!";
}
return `This function's caller was ${myFunc.caller}`;
}
重建调用栈和递归
请注意,在递归的情况下,您无法使用此属性重建调用栈。考虑以下情况:
function f(n) {
g(n - 1);
}
function g(n) {
if (n > 0) {
f(n);
} else {
stop();
}
}
f(2);
调用 stop() 时,调用栈将是:
f(2) -> g(1) -> f(1) -> g(0) -> stop()
以下为真:
stop.caller === g && f.caller === g && g.caller === f;
因此,如果您尝试在 stop() 函数中像这样获取堆栈跟踪:
let f = stop;
let stack = "Stack trace:";
while (f) {
stack += `\n${f.name}`;
f = f.caller;
}
循环将永远不会停止。
严格模式 caller
如果调用者是严格模式函数,则 caller 的值为 null。
function callerFunc() {
calleeFunc();
}
function strictCallerFunc() {
"use strict";
calleeFunc();
}
function calleeFunc() {
console.log(calleeFunc.caller);
}
(function () {
callerFunc();
})();
// Logs [Function: callerFunc]
(function () {
strictCallerFunc();
})();
// Logs null
规范
不属于任何标准。
浏览器兼容性
加载中…