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

规范

不属于任何标准。

浏览器兼容性

BCD tables only load in the browser

参见