Function.prototype.caller

非标准:此功能是非标准的,并且不在标准轨道上。请勿在面向 Web 的生产站点上使用它:它不会对每个用户都起作用。实现之间也可能存在很大的不兼容性,并且行为将来可能会发生变化。

已弃用:此功能不再推荐。尽管某些浏览器可能仍然支持它,但它可能已从相关的 Web 标准中删除,可能正在被删除,或者可能仅出于兼容性目的而保留。避免使用它,并尽可能更新现有代码;请参阅此页面底部的兼容性表,以指导您的决策。请注意,此功能可能随时停止工作。

注意:严格模式中,访问函数的caller会抛出错误 - API 已删除,没有替换。这样做是为了防止代码能够“遍历堆栈”,这既会带来安全风险,又严重限制了内联和尾调用优化等优化的可能性。有关更多说明,您可以阅读arguments.callee弃用的理由

callerFunction实例的访问器属性,它返回调用此函数的函数。对于严格、箭头、异步和生成器函数,访问caller属性会抛出TypeError

描述

如果函数f由顶级代码调用,则f.caller的值为null;否则为调用f的函数。如果调用f的函数是严格模式函数,则f.caller的值也为null

请注意,ECMAScript 规范指定的唯一行为是Function.prototype具有一个初始的caller访问器,该访问器对于任何getset请求都无条件地抛出TypeError(称为“毒丸访问器”),并且不允许实现更改此语义,除非对于非严格普通函数,在这种情况下,它不得具有严格模式函数的值。caller属性的实际行为(如果它不是抛出错误),是实现定义的。例如,Chrome 将其定义为自己的数据属性,而 Firefox 和 Safari 扩展了初始的毒丸Function.prototype.caller访问器以专门处理非严格函数的this值。

js
(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属性的值。

js
function myFunc() {
  if (myFunc.caller === null) {
    return "The function was called from the top!";
  } else {
    return `This function's caller was ${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();
})();
// Logs [Function: callerFunc]

(function () {
  strictCallerFunc();
})();
// Logs null

规范

不属于任何标准。

浏览器兼容性

BCD 表仅在启用 JavaScript 的浏览器中加载。

另请参阅