Function.prototype.caller

非標準:此特性未標準化。我們不建議在生產環境中使用非標準特性,因為它們瀏覽器支援有限,並且可能會更改或被移除。但是,在沒有標準選項的特定情況下,它們可以是合適的替代方案。

已棄用:此特性不再推薦。雖然某些瀏覽器可能仍然支援它,但它可能已經從相關的網路標準中刪除,可能正在刪除過程中,或者可能僅為相容性目的而保留。請避免使用它,如果可能,請更新現有程式碼;請參閱本頁底部的相容性表格以指導您的決策。請注意,此特性可能隨時停止工作。

注意:嚴格模式下,訪問函式的 caller 會丟擲錯誤 — 該 API 已被移除且沒有替代方案。這是為了防止程式碼能夠“遍歷呼叫棧”,這既帶來了安全風險,也嚴重限制了內聯和尾呼叫最佳化等最佳化的可能性。有關更多解釋,您可以閱讀 arguments.callee 棄用的理由

caller 屬性是 Function 例項的一個訪問器屬性,它返回呼叫此函式的函式。對於 嚴格模式、箭頭函式、非同步函式和生成器函式,訪問 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!";
  }
  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

規範

不屬於任何標準。

瀏覽器相容性

另見