Spec-Zone.ru › JavaScript

arguments.callee

Baseline Ограниченная доступность

Эта функция не является Baseline, так как она не работает в некоторых из наиболее широко используемых браузеров.

Устарело: Эта функция больше не рекомендуется. Хотя некоторые браузеры могут по-прежнему поддерживать ее, она уже может быть удалена из соответствующих веб-стандартов, находиться в процессе удаления или сохранена только для целей совместимости. Избегайте ее использования и, по возможности, обновите существующий код; см. таблицу совместимости внизу этой страницы, чтобы принять решение. Имейте в виду, что эта функция может перестать работать в любой момент.

Примечание: Доступ к arguments.callee в строгом режиме вызовет TypeError. Если функция должна ссылаться сама на себя, либо дайте функциональному выражению имя, либо используйте объявление функции.

Свойство данных arguments.callee содержит текущую выполняемую функцию, к которой относятся аргументы.

Значение

Ссылка на текущую выполняемую функцию.

Атрибуты свойства arguments.callee
Записываемое да
Перечисляемое нет
Настраиваемое да

Примечание: callee является свойством данных только в нестрогих функциях с простыми параметрами (в этом случае объект arguments также автоматически синхронизируется). В противном случае это свойство доступа, геттер и сеттер которого выбрасывают TypeError.

Описание

callee — это свойство объекта arguments. Оно может использоваться для ссылки на текущую выполняемую функцию внутри тела этой функции. Это полезно, когда имя функции неизвестно, например, внутри функционального выражения без имени (также называемого "анонимными функциями").

(Нижеследующий текст в значительной степени адаптирован из ответа на Stack Overflow от olliej)

Ранние версии JavaScript не разрешали именованные функциональные выражения, и по этой причине вы не могли создать рекурсивное функциональное выражение.

Например, этот синтаксис работал:

function factorial(n) {
  return n <= 1 ? 1 : factorial(n - 1) * n;
}

[1, 2, 3, 4, 5].map(factorial);

но:

[1, 2, 3, 4, 5].map(function (n) {
  return n <= 1 ? 1 : /* what goes here? */ (n - 1) * n;
});

не работал. Для обхода этой проблемы был добавлен arguments.callee, чтобы вы могли делать

[1, 2, 3, 4, 5].map(function (n) {
  return n <= 1 ? 1 : arguments.callee(n - 1) * n;
});

Однако дизайн arguments.callee имеет несколько проблем. Первая проблема заключается в том, что рекурсивный вызов будет иметь другое значение this. Например:

function sillyFunction(recursed) {
  if (this !== globalThis) {
    console.log("This is:", this);
  } else {
    console.log("This is the global");
  }

  if (!recursed) {
    return arguments.callee(true);
  }
}

sillyFunction();
// This is the global
// This is: [object Arguments]

Кроме того, ссылки на arguments.callee делают невозможным встраивание и хвостовую рекурсию в общем случае. (Вы можете добиться этого в отдельных случаях с помощью трассировки и т. д., но даже лучший код будет субоптимальным из-за проверок, которые иначе не потребовались бы.)

ECMAScript 3 решил эти проблемы, разрешив именованные функциональные выражения. Например:

[1, 2, 3, 4, 5].map(function factorial(n) {
  return n <= 1 ? 1 : factorial(n - 1) * n;
});

Это имеет множество преимуществ:

  • функция может вызываться как любая другая из вашего кода
  • она не создает переменную во внешней области видимости (кроме IE 8 и ниже)
  • она имеет лучшую производительность, чем доступ к объекту arguments

Строгий режим запретил другие свойства, утекающие информацию о стеке, такие как свойство caller функций. Это связано с тем, что просмотр стека вызовов имеет один основной эффект: он делает большое количество оптимизаций невозможным или гораздо более трудным. Например, если вы не можете гарантировать, что функция f не вызовет неизвестную функцию, невозможно встроить f.

function f(a, b, c, d, e) {
  return a ? b * c : d * e;
}

Если интерпретатор JavaScript не может гарантировать, что все предоставленные аргументы являются числами в момент вызова, ему необходимо либо вставить проверки для всех аргументов перед встраиваемым кодом, либо он не может встроить функцию. Это означает, что любой вызываемый сайт, который мог быть тривиально встроен, накапливает большое количество защитных механизмов. Теперь в этом конкретном случае умный интерпретатор должен уметь перестраивать проверки, чтобы они были более оптимальными и не проверяли значения, которые не будут использоваться. Однако во многих случаях это просто невозможно, и поэтому становится невозможным встраивание.

Примеры

Использование arguments.callee в анонимной рекурсивной функции

Рекурсивная функция должна уметь ссылаться сама на себя. Обычно функция ссылается на себя по своему имени. Однако анонимная функция (которую можно создать с помощью функционального выражения или конструктора Function) не имеет имени. Поэтому, если нет доступной переменной, ссылающейся на нее, единственный способ, которым функция может ссылаться сама на себя, — это через arguments.callee.

Следующий пример определяет функцию, которая, в свою очередь, определяет и возвращает факториальную функцию. Этот пример не очень практичен, и почти нет случаев, когда тот же результат нельзя было бы достичь с помощью именованных функциональных выражений.

function create() {
  return function (n) {
    if (n <= 1) {
      return 1;
    }
    return n * arguments.callee(n - 1);
  };
}

const result = create()(5); // returns 120 (5 * 4 * 3 * 2 * 1)

Рекурсия анонимных функций с Y-комбинатором

Хотя функциональные выражения теперь могут быть именованы, стрелочные функции всегда остаются анонимными, что означает, что они не могут ссылаться на себя, не будучи предварительно присвоенными переменной. К счастью, в лямбда-исчислении есть очень хорошее решение, позволяющее функции быть как анонимной, так и самореферентной. Эта техника называется Y-комбинатором. Здесь мы не будем объяснять, *как* это работает, только *то*, что это работает.

// The Y-combinator: a utility function!
const Y = (hof) => ((x) => x(x))((x) => hof((y) => x(x)(y)));

console.log(
  [1, 2, 3, 4, 5].map(
    // Wrap the higher-order function in the Y-combinator
    // "factorial" is not a function's name: it's introduced as a parameter
    Y((factorial) => (n) => (n <= 1 ? 1 : factorial(n - 1) * n)),
  ),
);
// [ 1, 2, 6, 24, 120 ]

Примечание: Этот метод выделяет новую замыкание для каждой итерации, что может значительно увеличить использование памяти. Он приведен здесь только для демонстрации возможности, но должен быть избегаем в продакшене. Вместо этого используйте временную переменную или именованное функциональное выражение.

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-arguments-exotic-objects

Совместимость с браузерами

Настольные Мобильные Сервер
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
callee
1
12
1
4
1
18
4
10.1
1
1.0
4.4
1
1.0.0
1.0
0.10.0

См. также

  • Руководство по функциям
  • Функции
  • arguments
  • Function.prototype.caller

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API