Function.prototype.caller

非标准: 该特性是非标准的,请尽量不要在生产环境中使用它!

已弃用: 不再推荐使用该特性。虽然一些浏览器仍然支持它,但也许已从相关的 web 标准中移除,也许正准备移除或出于兼容性而保留。请尽量不要使用该特性,并更新现有的代码;参见本页面底部的兼容性表格以指导你作出决定。请注意,该特性随时可能无法正常工作。

备注:严格模式下,访问函数的 caller 属性会抛出错误——该 API 已被移除且没有替代品。这是为了防止代码能够“遍历堆栈”,这既存在安全风险,也严重限制了内联和尾调用优化等优化的可能性。如需更多解释,请阅读 arguments.callee 的弃用原因

Function 实例的 caller 访问器属性返回调用该函数的函数。对于严格模式、箭头函数、异步函数和生成器函数来说,访问 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 值。

js
(function f() {
  if (Object.hasOwn(f, "caller")) {
    console.log(
      "caller 是一个自有属性,具有描述符",
      Object.getOwnPropertyDescriptor(f, "caller"),
    );
  } else {
    console.log(
      "f 没有名为 caller 的自有属性。尝试获取 f.[[Prototype]].caller",
    );
    console.log(
      Object.getOwnPropertyDescriptor(
        Object.getPrototypeOf(f),
        "caller",
      ).get.call(f),
    );
  }
})();

// 在 Chrome 中:
// caller 是一个自有属性,具有描述符 {value: null, writable: false, enumerable: false, configurable: false}

// 在 Firefox 中:
// f 没有名为 caller 的自有属性。尝试获取 f.[[Prototype]].caller
// null

此属性取代了 arguments 对象的已弃用的 arguments.caller 属性。

出于安全原因,特殊属性 __caller__ 已被移除,它返回调用者的激活对象,从而允许重建堆栈。

示例

检查函数 caller 属性的值

以下代码检查函数的 caller 属性的值。

js
function myFunc() {
  if (myFunc.caller === null) {
    return "该函数是从顶层调用的!";
  } else {
    return `该函数的调用者是 ${myFunc.caller}`;
  }
}

重建调用堆栈和递归

请注意,在递归的情况下,你不能使用该属性重建调用堆栈。参考以下示例:

js
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()

以下是条件表达式为真:

js
stop.caller === g && f.caller === g && g.caller === f;

因此,如果你尝试像这样在 stop() 函数中获取堆栈跟踪:

js
let f = stop;
let stack = "Stack trace:";
while (f) {
  stack += `\n${f.name}`;
  f = f.caller;
}

循环永远不会停止。

严格模式下的 caller

如果调用者是严格模式函数,则 caller 的值为 null

js
function callerFunc() {
  calleeFunc();
}

function strictCallerFunc() {
  "use strict";
  calleeFunc();
}

function calleeFunc() {
  console.log(calleeFunc.caller);
}

(function () {
  callerFunc();
})();
// 输出 [Function: callerFunc]

(function () {
  strictCallerFunc();
})();
// 输出 null

规范

不属于任何标准。

浏览器兼容性

Report problems with this compatibility data on GitHub
desktopmobileserver
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Deno
Node.js
caller
DeprecatedNon-standard

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
Non-standard. Check cross-browser support before using.
Deprecated. Not for use in new websites.

参见