¿Por qué la propiedad arguments.callee.caller quedó obsoleta en JavaScript?

StackOverflow https://stackoverflow.com/questions/103598

  •  01-07-2019
  •  | 
  •  

Pregunta

¿Por qué fue el arguments.callee.caller ¿Propiedad obsoleta en JavaScript?

Se agregó y luego quedó obsoleto en JavaScript, pero ECMAScript lo omitió por completo.Algunos navegadores (Mozilla, IE) siempre lo han admitido y no tienen planes de eliminarlo.Otros (Safari, Opera) han adoptado la compatibilidad con él, pero la compatibilidad con navegadores más antiguos no es confiable.

¿Existe una buena razón para dejar esta valiosa funcionalidad en el limbo?

(O alternativamente, ¿hay una mejor manera de controlar la función de llamada?)

¿Fue útil?

Solución

Las primeras versiones de JavaScript no permitían expresiones de funciones con nombre y, por eso, no podíamos crear una expresión de función 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 solucionar esto, arguments.callee Se agregó para que pudiéramos hacer:

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

Sin embargo, esta fue en realidad una solución realmente mala ya que esto (junto con otros argumentos, problemas con el destinatario y la persona que llama) hace que la recursividad en línea y la cola sea imposible en el caso general (puede lograrlo en casos selectos mediante el rastreo, etc., pero incluso el mejor código es subóptimo debido a comprobaciones que de otro modo no serían necesarias).El otro problema importante es que la llamada recursiva obtendrá una diferente this valor, por ejemplo:

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 todos modos, EcmaScript 3 resolvió estos problemas al permitir expresiones de funciones con nombre, por ejemplo:

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

Esto tiene numerosos beneficios:

  • La función se puede llamar como cualquier otra desde dentro de su código.

  • No contamina el espacio de nombres.

  • El valor de this no cambia.

  • Es más eficaz (acceder a la objeto de argumentos es caro).

Ups,

Me acabo de dar cuenta de que además de todo lo demás la pregunta era sobre arguments.callee.caller, o más específicamente Function.caller.

En cualquier momento puedes encontrar el llamador más profundo de cualquier función en la pila y, como dije anteriormente, mirar la pila de llamadas tiene un único efecto importante:Hace que una gran cantidad de optimizaciones sean imposibles o mucho más difíciles.

P.ej.si no podemos garantizar que una función f no llamará a una función desconocida, entonces no es posible insertarla f.Básicamente, significa que cualquier sitio de llamada que pueda haber sido trivialmente inlinable acumula una gran cantidad de guardias, tome:

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

Si el intérprete js no puede garantizar que todos los argumentos proporcionados sean números en el momento en que se realiza la llamada, debe insertar comprobaciones para todos los argumentos antes del código insertado o no puede insertar la función.

Ahora bien, en este caso particular, un intérprete inteligente debería poder reorganizar las comprobaciones para que sean más óptimas y no comprobar ningún valor que no se utilizaría.Sin embargo, en muchos casos eso simplemente no es posible y, por lo tanto, resulta imposible incorporarlo.

Otros consejos

arguments.callee.callejem es no en desuso, aunque hace uso de la Function.callejem propiedad.(arguments.callee solo le dará una referencia a la función actual)

  • Function.callejem, aunque no es estándar según ECMA3, se implementa en todos todos los principales navegadores actuales.
  • arguments.callejem es en desuso a favor de Function.callejem, y no está implementado en algunos de los principales navegadores actuales (p. ej.Firefox 3).

Entonces, la situación no es ideal, pero si desea acceder a la función de llamada en Javascript en todos los navegadores principales, puede usar el Function.callejem propiedad, ya sea a la que se accede directamente en una referencia de función nombrada o desde una función anónima a través de arguments.callee propiedad.

Es mejor usar funciones nombradas que argumentos.callee:

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

es mejor que

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

La función nombrada tendrá acceso a su llamador a través del llamador propiedad:

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

cual es mejor que

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

La desaprobación se debe al ECMAScript actual. criterios de diseño.

Sólo una extensión.El valor de "esto" cambia durante la recursividad.En el siguiente ejemplo (modificado), factorial obtiene el objeto {foo:true}.

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

El factorial llamado por primera vez obtiene el objeto, pero esto no es cierto para las llamadas recursivas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top