Почему свойство arguments.callee.caller устарело в JavaScript?

Почему свойство arguments.callee.caller было объявлено устаревшим в JavaScript?

Он был добавлен, а затем объявлен устаревшим в JavaScript, но полностью исключен в ECMAScript. Некоторые браузеры (Mozilla, IE) всегда поддерживали его и не планируют отменять поддержку. Другие (Safari, Opera) приняли его поддержку, но поддержка в старых браузерах ненадежна.

Есть ли веская причина оставить эту ценную функцию в подвешенном состоянии?

(Или, альтернативно, есть лучший способ захватить дескриптор вызывающей функции?)

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

olliej 25.10.2008 06:04

(Почти все браузеры когда-то делали это, например, эта функция (и сам JS) исходит от Netscape, XHR возник в IE, Canvas в Safari и т. д. Некоторые из них полезны и используются другими браузерами. со временем (js, canvas, xhr - все примеры), некоторые (.callee) - нет.

olliej 25.10.2008 06:08

@olliej Ваш комментарий о его поддержке, потому что он используется, а не потому, что он является стандартом (или даже несмотря на то, что он устарел в стандарте), очень верен! Вот почему я начал игнорировать стандарты всякий раз, когда мне казалось, что они мне не помогают. Мы, как разработчики, можем формировать направление стандартов, используя то, что работает, а не то, что в спецификации сказано, что мы должны делать. Так мы вернули <b> и <i> (да, в какой-то момент они устарели).

Stijn de Witt 17.04.2017 23:22
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
215
3
77 909
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Лучше использовать именованные функции, чем arguments.callee:

 function foo () {
     ... foo() ...
 }

лучше, чем

 function () {
     ... arguments.callee() ...
 }

Именованная функция будет иметь доступ к вызывающей стороне через свойство звонящий:

 function foo () {
     alert(foo.caller);
 }

что лучше чем

 function foo () {
     alert(arguments.callee.caller);
 }

Устарение связано с текущим ECMAScript принципы дизайна.

Можете ли вы описать, почему использование названной функции лучше? Разве никогда не нужно использовать вызываемый объект в анонимной функции?

AnthonyWJones 19.09.2008 22:49

Если вы используете вызываемый объект в анонимной функции, то у вас есть функция, которая не должна быть анонимной.

Prestaul 19.09.2008 23:42

иногда самый простой способ отладки - использовать .caller (). В таких случаях именованные функции не помогут - вы пытаетесь выяснить, какая функция выполняет вызов.

SamGoody 13.12.2010 14:02

Определите лучше. Например, IE6-8 назвали причуды функций, а arguments.callee работает.

cmc 21.01.2012 06:27

Помимо причуд IE6-8, он также делает код тесно связанным. Если имена объектов и / или функций жестко запрограммированы, то, как упоминают ardsasd и rsk82, существуют серьезные опасности рефакторинга, которые только увеличиваются по мере увеличения базового размера кода. Модульные тесты - это линия защиты, и я использую их, но они все еще не тот ответ, который действительно насытит меня лично в отношении этой проблемы жесткого кодирования.

Jasmine Hegman 01.05.2013 22:43
Ответ принят как подходящий

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

 // This snippet will work:
 function factorial(n) {
     return (!(n>1))? 1 : factorial(n-1)*n;
 }
 [1,2,3,4,5].map(factorial);


 // But this snippet will not:
 [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;
 });

Однако на самом деле это было действительно плохим решением, поскольку это (в сочетании с другими аргументами, вызываемыми и вызывающими проблемами) делает невозможным встраивание и хвостовую рекурсию в общем случае (вы можете добиться этого в отдельных случаях с помощью трассировки и т. д., Но даже лучший код является неоптимальным из-за проверок, которые в противном случае не потребовались бы). Другая важная проблема заключается в том, что рекурсивный вызов получит другое значение this, например:

var global = this;
var sillyFunction = function (recursed) {
    if (!recursed)
        return arguments.callee(true);
    if (this !== global)
        alert("This is: " + this);
    else
        alert("This is the global");
}
sillyFunction();

Как бы то ни было, EcmaScript 3 решил эти проблемы, разрешив именованные выражения функций, например:

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

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

  • Функцию можно вызывать, как и любую другую, из вашего кода.

  • Это не загрязняет пространство имен.

  • Значение this не меняется.

  • Он более производительный (доступ к объект аргументов стоит дорого).

Ой,

Сразу понял, что кроме всего прочего вопрос был про arguments.callee.caller, а точнее Function.caller.

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

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

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

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

Теперь в этом конкретном случае умный интерпретатор должен иметь возможность изменить порядок проверок, чтобы они были более оптимальными, и не проверять какие-либо значения, которые не будут использоваться. Однако во многих случаях это просто невозможно, и поэтому становится невозможным встраивание.

Вы говорите, что он устарел только потому, что его сложно оптимизировать? Это довольно глупо.

Thomas Eding 18.08.2010 03:57

Нет, я перечислил ряд причин, помимо того, что это затрудняет оптимизацию (хотя в целом история показала, что вещи, которые трудно оптимизировать, также имеют семантику, которой люди не могут следовать)

olliej 27.08.2010 13:23

Аргумент это немного ложный, его значение может быть установлено вызовом, если оно важно. Обычно он не используется (по крайней мере, у меня никогда не было проблем с ним в рекурсивных функциях). Вызов функции по имени имеет те же проблемы с this, поэтому я думаю, что это не имеет значения в отношении того, является ли вызываемый хорошим или плохим. Кроме того, вызываемый и звонящий "устарели" только в строгом режиме (ECMAscript ed 5, декабрь 2009 г.), но я полагаю, что это не было известно в 2008 г., когда опубликовал olliej.

RobG 27.05.2011 07:24

) До сих пор не вижу логики. На любом языке с функциями первого класса очевидна ценность возможности определить тело функции, которое может ссылаться на себя, без необходимости знать i

Mark Reed 20.10.2011 23:41

arguments.callee.caller дает вам функцию, которая вызвала вас, а не функцию, в которой вы находитесь, что не слишком полезно в реальном коде и приводит к тому, что встраивание, хвостовые вызовы и т. д. становятся несостоятельными.

olliej 21.10.2011 20:13

Обратите внимание, что вам не нужны именованные функции (или arguments.callee) для создания рекурсивных функций, так как вы можете использовать Y комбинатор.

Suzanne Dupéron 17.08.2012 11:20

Устаревание из-за другого this тоже глупо. Для этого у нас есть Function.prototype.call и Function.prototype.apply.

Swivel 27.06.2013 02:40

РобГ указал на это, но я не думаю, что все было так ясно: рекурсивное использование именованной функции сохранит значение this, только если this является глобальной областью. Во всех остальных случаях значение thisбуду изменяется после первого рекурсивного вызова, поэтому я думаю, что части вашего ответа, ссылающиеся на сохранение this, на самом деле не действительны.

JLRishe 22.01.2014 17:31

Что касается введения arguments.callee, ради человечества, почему бы не остановиться на анонимных встроенных функциях вместе и просто передать ссылку на функцию таким функциям, как map. Это хорошая идея не потому, что JS позволяет вам писать такой код. Это скрывает структуру кода, и если вы не назовете их, они будут отображаться как «анонимные функции» в отладчиках и профилировщиках. Я бы хотел, чтобы разработчики JS изучили некоторые базовые концепции программирования, чтобы перестать писать нечитаемый, не исправляемый, непрофильный, плохо спроектированный и, следовательно, обычно ошибочный код.

user1115652 30.01.2015 20:05

@nus Если вы используете анонимные функции, передавая их в качестве обработчиков событий, это ничего не скрывает. Кроме того, он проясняет и гарантирует, что функция вызывается только при срабатывании события.

fishbone 18.03.2015 14:49

@olliej. для чего ! в !(n>1))? 1

Abhi 05.07.2016 14:49

@nus. для чего ! в !(n>1))? 1

Abhi 05.07.2016 14:50

@iLiveInAPineappleUnderTheSea ! означает НЕ как логический оператор в большинстве языков программирования, проверять операторы javascript. Весь оператор return (!(n>1))? 1 : factorial(n-1)*n; переводится как: Если n не больше 1, return 1 иначе вернет результат факториала ... В любом случае его было бы легче читать, удалив лишние скобки и отрицание: return n<=1 ? 1 : factorial( n-1 ) * n

user1115652 05.07.2016 16:03

Собственно, до ES3 был нет функционального выражения. вместо него был конструктор Function. поэтому в спецификации сказано:> Анонимные функции создаются динамически с использованием встроенного объекта Function в качестве конструктора, который называется функцией создания экземпляра> Свойство создается с именем вызываемого и атрибутами свойства {DontEnum}. Начальным значением этого свойства является выполняемый объект функции. Это позволяет анонимным функциям быть рекурсивными.

ENvironmentSet 31.01.2019 01:10

Эмм ... Почему этот ответ почти дословный, что на этой странице? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

Andrew 18.10.2019 23:10

arguments.callee.caller является устаревшим нет, хотя он использует свойство Function.caller. (arguments.callee просто даст вам ссылку на текущую функцию)

  • Function.caller, хотя и нестандартный согласно ECMA3, реализуется через все текущие основные браузеры.
  • arguments.callerявляется устарел в пользу Function.caller и не реализован в некоторых текущих основных браузерах (например, Firefox 3).

Таким образом, ситуация далеко не идеальная, но если вы хотите получить доступ к вызывающей функции в Javascript во всех основных браузерах, вы можете использовать свойство Function.caller, доступ к которому осуществляется либо непосредственно по ссылке на именованную функцию, либо из анонимной функции через свойство arguments.callee. .

Это лучшее объяснение того, что является устаревшим, а что нет, очень полезно. Хороший пример того, что Function.caller не может сделать (получить трассировку стека рекурсивных функций), см. В developer.mozilla.org/en/JavaScript/Reference/Global_Objects‌ /…

Juan Mendes 09.11.2011 23:18

Хотя в строгом режиме arguments.callee запрещен. Мне тоже стало грустно, но лучше больше не использовать.

Gras Double 15.04.2015 02:25

Гиперссылка arguments.callee, которая у вас есть на MDN, говорит, что она удаляется в строгом режиме. Разве это не то же самое, что и устаревшее?

styfle 11.04.2017 23:19

Обратите внимание, что arguments.callee.caller не рекомендуется в строгом режиме ES5: «Еще одна устаревшая функция - arguments.callee.caller или, более конкретно, Function.caller». (Источник)

thdoan 16.05.2018 13:42

Просто расширение. Значение this изменяется во время рекурсии. В следующем (измененном) примере факториал получает объект {foo: true}.

[1,2,3,4,5].map(function factorial(n) {
  console.info(this);
  return (!(n>1))? 1 : factorial(n-1)*n;
},     {foo:true}     );

Факториал, вызываемый в первый раз, получает объект, но это неверно для рекурсивных вызовов.

Потому что вы делаете это неправильно. Если this необходимо поддерживать, напишите factorial.call(this, n-1), который я обнаружил при написании рекурсивного кода, что обычно нет this, или this относится к некоторому узлу в дереве, и на самом деле хорошо, что он изменяется.

Stijn de Witt 17.04.2017 23:33

Другие вопросы по теме