Почему были такие споры.вызываемый.свойство caller устарело в JavaScript?
почему arguments.callee.caller свойство устарело в JavaScript?
Он был добавлен, а затем устарел в JavaScript, но он был полностью опущен ECMAScript. Некоторые браузеры (Mozilla, IE) всегда поддерживали его и не имеют никаких планов на карте, чтобы удалить поддержку. Другие (Safari, Opera) приняли поддержку для него, но поддержка на старых браузерах ненадежна.
есть ли веская причина, чтобы поставить эту ценную функциональность в подвешенном состоянии?
(или кроме того, есть ли лучший способ захватить дескриптор вызывающей функции?)
5 ответов:
ранние версии 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 не может гарантировать, что все предоставленные аргументы являются числами в момент выполнения вызова, ему необходимо либо вставить проверки для всех аргументов перед встроенным кодом, либо он не может встроить функцию.
теперь в этом конкретном случае умный интерпретатор должен быть в состоянии переставить проверки, чтобы быть более оптимальным и не проверять любые значения, которые не будут использоваться. Однако во многих случаях это просто невозможно и поэтому становится невозможным инлайн.
arguments.callee.callerи не устарел, хотя он используетFunction.callerсобственность. (arguments.calleeпросто дать вам ссылку на текущую функцию)
Function.caller, хотя и нестандартный в соответствии с ECMA3, реализован через все современные браузеры.arguments.callerи deprecated в пользуFunction.caller, и не реализуется в некоторых текущих основных браузеры (например, Firefox 3).таким образом, ситуация не идеальна, но если вы хотите получить доступ к вызывающей функции в Javascript во всех основных браузерах, вы можете использовать
Function.callerсвойство, доступ к которому осуществляется либо непосредственно по ссылке на именованную функцию, либо из анонимной функции черезarguments.calleeсобственность.
лучше использовать имени функции чем аргументов.абонент:
function foo () { ... foo() ... }лучше, чем
function () { ... arguments.callee() ... }именованная функция будет иметь доступ к своему абоненту через caller свойства:
function foo () { alert(foo.caller); }лучше, чем
function foo () { alert(arguments.callee.caller); }устаревание связано с текущим ECMAScript принципы проектирования.
просто расширение. Значение "this" изменяется во время рекурсии. В следующем (измененном) примере факториал получает объект {foo:true}.
[1,2,3,4,5].map(function factorial(n) { console.log(this); return (!(n>1))? 1 : factorial(n-1)*n; }, {foo:true} );факториал называется первый раз получает объект, но это не верно для рекурсивных вызовов.