Почему были такие споры.вызываемый.свойство 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} );
факториал называется первый раз получает объект, но это не верно для рекурсивных вызовов.