Pergunta

Por que a propriedade arguments.callee.caller depreciado em JavaScript?

Foi adicionado e, em seguida, depreciado em JavaScript, mas foi omitido por completo, ECMAScript. Alguns navegador (Mozilla, IE) sempre apoiaram-lo e não tem planos no mapa para o suporte de remoção. Outros (Safari, Opera) adotaram o suporte para ele, mas o suporte em navegadores mais antigos não é confiável.

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

(ou alternadamente, há uma maneira melhor para agarrar uma alça sobre a função chamando?)

Foi útil?

Solução

As primeiras versões do JavaScript não permitiu chamado expressões de função, e por isso nós não poderíamos fazer uma expressão de função 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 este problema, foi adicionado arguments.callee para que pudéssemos fazer:

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

No entanto, este foi realmente uma solução muito ruim como esta (em conjunto com outros argumentos, receptor, e questões de chamadas) fazer inlining e cauda recursão impossível no caso geral (você pode alcançá-lo em casos selecionados por meio de rastreamento etc, mas mesmo o melhor código é sub ideal devido aos controlos que não seria de outro modo necessário). O outro grande problema é que a chamada recursiva terá um valor this 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 resolvidas estas questões, permitindo expressões função chamada, por exemplo:.

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

Isto tem inúmeros benefícios:

  • A função pode ser chamado como qualquer outro de dentro do seu código.

  • Ele não polui o namespace.

  • O valor da this não muda.

  • É mais performance (acessando os argumentos objeto é caro).

Whoops,

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

Em qualquer ponto no tempo, você pode encontrar o chamador mais profunda de qualquer função na pilha, e como eu disse acima, olhando para a pilha de chamadas tem um efeito importante único: Faz um grande número de otimizações impossível, ou muito muito mais difícil.

Por exemplo. se não podemos garantir que uma função f não vai chamar uma função desconhecida, então não é possível f embutido. Basicamente, isso significa que qualquer site de chamada que pode ter sido trivialmente elegíveis para uso inline acumula um grande número de guardas, pegue:

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

Se os js intérprete não pode garantir que todos os argumentos apresentados são números no ponto em que a chamada é feita, ele precisa tanto de inserção verifica todos os argumentos antes do código inline, ou ele não pode linha da função.

Agora, neste caso particular, um intérprete inteligente deve ser capaz de reorganizar os controlos deverão ser mais otimizado e não verificar quaisquer valores que não seriam utilizados. No entanto, em muitos casos isso não é possível e, portanto, torna-se impossível em linha.

Outras dicas

arguments.callee.caller é não deprecated, apesar de não fazer uso do Function.caller propriedade. ( arguments.callee vai apenas dar-lhe uma referência para a função atual)

  • Function.caller, embora não-padrão de acordo com ECMA3, é implementado através de todas as correntes principais navegadores .
  • arguments.caller é deprecated em favor de Function.caller, e não é implementado em algumas correntes principais navegadores (por exemplo Firefox 3).

Assim, a situação é menos do que o ideal, mas se você quiser acessar a função de chamada em Javascript em todos os principais navegadores, você pode usar a propriedade Function.caller, seja acessado diretamente em uma referência função chamada, ou a partir de dentro de uma função anônima via a propriedade arguments.callee.

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

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

é melhor do que

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

A função chamada terá acesso ao seu interlocutor através do chamador propriedade:

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

que é melhor do que

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

A depreciação é devido à corrente ECMAScript princípios de design .

Apenas uma extensão. O valor de "este" muda durante a recursividade. No seguinte exemplo (modificado), fatorial recebe o {foo: true}. Objeto

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

factorial chamado primeira vez obtém o objeto, mas isso não é verdade para as chamadas recursivas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top