Function.prototype.caller

Non-standard: This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

Deprecated: This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible; see the compatibility table at the bottom of this page to guide your decision. Be aware that this feature may cease to work at any time.

注意:在 严格模式 中,访问函数的 caller 会引发错误 - API 被删除且没有替换。这是为了防止代码能够 "走栈",这既会带来安全风险,也会严重限制内联和尾调用优化等优化的可能性。更多解释,你可以阅读 废弃 arguments.callee 的理由

¥Note: In strict mode, accessing caller of a function throws an error — the API is removed with no replacement. This is to prevent code from being able to "walk the stack", which both poses security risks and severely limits the possibility of optimizations like inlining and tail-call optimization. For more explanation, you can read the rationale for the deprecation of arguments.callee.

Function 实例的 caller 访问器属性返回调用该函数的函数。对于 strict、箭头、异步和生成器函数,访问 caller 属性会抛出 TypeError

¥The caller accessor property of Function instances returns the function that invoked this function. For strict, arrow, async, and generator functions, accessing the caller property throws a TypeError.

描述

¥Description

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

¥If the function f was invoked by the top-level code, the value of f.caller is null; otherwise it's the function that called f. If the function that called f is a strict mode function, the value of f.caller is also null.

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

¥Note that the only behavior specified by the ECMAScript specification is that Function.prototype has an initial caller accessor that unconditionally throws a TypeError for any get or set request (known as a "poison pill accessor"), and that implementations are not allowed to change this semantic for any function except non-strict plain functions, in which case it must not have the value of a strict mode function. The actual behavior of the caller property, if it's anything other than throwing an error, is implementation-defined. For example, Chrome defines it as an own data property, while Firefox and Safari extend the initial poison-pill Function.prototype.caller accessor to specially handle this values that are non-strict functions.

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 属性。

¥This property replaces the obsolete arguments.caller property of the arguments object.

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

¥The special property __caller__, which returned the activation object of the caller thus allowing to reconstruct the stack, was removed for security reasons.

示例

¥Examples

检查函数的调用者属性的值

¥Checking the value of a function's caller property

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

¥The following code checks the value a function's caller property.

js
function myFunc() {
  if (myFunc.caller === null) {
    return "The function was called from the top!";
  } else {
    return `This function's caller was ${myFunc.caller}`;
  }
}

重构堆栈和递归

¥Reconstructing the stack and recursion

请注意,在递归的情况下,你无法使用此属性重建调用堆栈。考虑:

¥Note that in case of recursion, you can't reconstruct the call stack using this property. Consider:

js
function f(n) {
  g(n - 1);
}
function g(n) {
  if (n > 0) {
    f(n);
  } else {
    stop();
  }
}
f(2);

此时 stop() 被调用,调用堆栈将是:

¥At the moment stop() is called the call stack will be:

f(2) -> g(1) -> f(1) -> g(0) -> stop()

以下是正确的:

¥The following is true:

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

因此,如果你尝试在 stop() 函数中获取堆栈跟踪,如下所示:

¥so if you tried to get the stack trace in the stop() function like this:

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

循环永远不会停止。

¥the loop would never stop.

严格模式调用者

¥Strict mode caller

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

¥If the caller is a strict mode function, the value of caller is 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

规范

¥Specifications

不属于任何标准。

¥Not part of any standard.

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看