Por que a propriedade arguments.callee.caller foi descontinuada em JavaScript?

Por que a propriedade arguments.callee.caller foi preterida em JavaScript?

Ele foi adicionado e, em seguida, obsoleto em JavaScript, mas foi totalmente omitido pelo ECMAScript. Alguns navegadores (Mozilla, IE) sempre o suportaram e não têm planos no mapa para remover o suporte. Outros (Safari, Opera) adotaram suporte para isso, mas o suporte em navegadores mais antigos não é confiável.

Existe uma boa razão para colocar esta valiosa funcionalidade no limbo?

(Ou alternadamente, existe uma maneira melhor de pegar um identificador na function de chamada?)

As primeiras versões do JavaScript não permitiam expressões de function nomeadas e, por causa disso, não poderíamos criar uma expressão de function recursiva:

  // 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; }); 

Para contornar isso, arguments.callee foi adicionado para que pudéssemos fazer:

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

No entanto, esta foi realmente uma solução muito ruim como isso (em conjunto com outros argumentos, callee e chamadas) fazer inlining e cauda recursion impossível no caso geral (você pode alcançá-lo em casos selecionados através de rastreamento etc, mas até mesmo o melhor código é sub-ótimo devido a verificações que de outra forma não seriam necessárias). A outra grande questão é que a chamada recursiva receberá um valor diferente, por exemplo:

 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(); 

De qualquer forma, EcmaScript 3 resolveu esses problemas, permitindo expressões de function nomeadas, por exemplo:

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

Isso tem vários benefícios:

  • A function pode ser chamada como qualquer outra dentro do seu código.

  • Não polui o espaço de nomes.

  • O valor this não muda.

  • É mais performático (acessar o object arguments é caro).

Ops

Apenas percebi que, além de tudo, a questão era sobre arguments.callee.caller , ou mais especificamente Function.caller .

A qualquer momento você pode encontrar o chamador mais profundo de qualquer function na pilha, e como eu disse acima, olhar para a pilha de chamadas tem um único efeito principal: torna impossível um grande número de otimizações, ou muito mais difícil.

Por exemplo. se não podemos garantir que uma function f não irá chamar uma function desconhecida, então não é possível embutir f . Basicamente, significa que qualquer site de chamada que possa ter sido trivialmente inline acumula um grande número de guardas, tome:

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

Se o interpretador js não puder garantir que todos os argumentos fornecidos sejam números no ponto em que a chamada é feita, ele precisará inserir verificações para todos os argumentos antes do código inlined, ou não poderá inline a function.

Agora, neste caso em particular, um intérprete inteligente deve ser capaz de reorganizar as verificações para ser mais ideal e não verificar quaisquer valores que não seriam usados. No entanto, em muitos casos isso não é possível e, portanto, torna-se impossível inline.

arguments.call ee .call er não é preterido, embora faça uso da propriedade Function.call er . ( arguments.call ee lhe dará uma referência para a function atual)

  • Function.call er , embora não padrão de acordo com o ECMA3, é implementado em todos os principais navegadores atuais .
  • arguments.call er está obsoleto em favor de Function.call er , e não é implementado em alguns dos principais navegadores atuais (por exemplo, Firefox 3).

Portanto, a situação é menos que ideal, mas se você quiser acessar a function de chamada em Javascript em todos os principais navegadores, você pode usar a propriedade Function.call er , acessada diretamente em uma referência de function nomeada ou de dentro de uma function anônima via a propriedade arguments.call ee .

É melhor usar funções nomeadas do que arguments.callee:

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

é melhor que

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

A function nomeada terá access ao seu chamador através da propriedade do chamador :

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

que é melhor que

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

A depreciação deve-se aos princípios atuais de design do ECMAScript.

Ainda há um argumento para se referir à function sem ter que codificar seu nome.

Apenas uma extensão. O valor de “this” muda durante a recursion. No seguinte exemplo (modificado), fatorial obtém o object {foo: true}.

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

fatorial chamado primeira vez obtém o object, mas isso não é verdade para chamadas recursivas.