Frage

Warum die arguments.callee.caller Eigenschaft wurde in JavaScript veraltet?

Es wurde hinzugefügt, und dann in JavaScript veraltet, aber es war insgesamt von ECMAScript weggelassen. Einige Browser (Mozilla, IE) habe es immer unterstützt und haben keine Pläne auf der Karte Unterstützung zu entfernen. Andere (Safari, Opera) haben ihre Unterstützung für sie angenommen, aber Unterstützung für ältere Browser ist unzuverlässig.

Sie haben einen guten Grund, diese wertvolle Funktionalität in der Schwebe zu setzen?

(oder alternativ gibt es einen besseren Weg, um einen Griff auf der rufenden Funktion zu greifen?)

War es hilfreich?

Lösung

Frühe Versionen von JavaScript erlauben nicht benannte Funktion Ausdrücke, und aus diesem Grund konnten wir nicht eine rekursive Funktion Ausdruck machen:

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

Um dies zu umgehen, arguments.callee hinzugefügt wurde, so dass wir tun könnten:

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

Allerdings war dies eigentlich eine wirklich schlechte Lösung, da dies (in Verbindung mit anderen Argumenten, Rufenen und Anruferfragen) macht inlining und Endrekursion unmöglich im allgemeinen Fall (Sie es in ausgewählten Fällen durch Tracing etc. erreichen können, aber auch der beste Code ist suboptimal aufgrund Kontrollen, die sonst nicht notwendig wären). Das andere große Problem ist, dass der rekursive Aufruf einen anderen this Wert erhalten wird, zum Beispiel:

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

Wie auch immer, EcmaScript 3 gelöst, diese Probleme durch benannte Funktion Ausdrücke erlaubt, z.

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

Das hat zahlreiche Vorteile:

  • Die Funktion kann wie jede andere aus Ihrem Code aufgerufen werden.

  • Es ist der Namensraum nicht verschmutzen.

  • Der Wert von this ändert sich nicht.

  • Es ist performanter (Zugriff auf die Argumente Objekt ist teuer).

Whoops,

gerade realisiert, dass zusätzlich zu allem anderen der Frage nach arguments.callee.caller war, oder genauer gesagt, Function.caller .

Zu jedem Zeitpunkt Sie die tiefste Anrufer jeder Funktion auf dem Stapel finden, und wie ich oben gesagt, bei dem Call-Stack suchen habe eine einzige große Wirkung: Es ist eine große Anzahl von Optimierungen unmöglich macht, oder viel viel schwieriger.

Eg. wenn wir nicht garantieren können, dass eine Funktion f nicht eine unbekannte Funktion aufrufen, dann ist es nicht möglich, Inline f. Grundsätzlich bedeutet dies, dass jeder Anruf Website, die auch gewesen sein mag trivial inlinable eine große Anzahl von Wachen sammelt sich nehmen:

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

Wenn der js Interpreter kann nicht garantieren, dass alle vorgesehenen Argumente Zahlen sind an dem Punkt, dass der Anruf getätigt wird, muss es entweder Einsatz überprüft alle Argumente vor dem inlined Code, oder es kann die Funktion nicht inline.

Jetzt in diesem speziellen Fall ein intelligenten Dolmetscher sollten die Kontrollen neu zu ordnen, um mehr optimal und nicht überprüft alle Werte zu sein, die nicht verwendet werden würden. Doch in vielen Fällen das ist einfach nicht möglich, und daher wird es unmöglich, inline.

Andere Tipps

arguments.callee.caller ist nicht ist veraltet, obwohl macht es die Verwendung des Function.caller Eigenschaft. ( arguments.callee geben Sie nur einen Verweis auf die aktuelle Funktion)

  • Function.caller, obwohl Nicht-Standard nach ECMA3 wird über alle aktuellen wichtigen Browser implementiert.
  • arguments.caller ist veraltet zugunsten von Function.caller und wird in einigen aktuellen gängigen Browsern (zB Firefox 3).
  • nicht implementiert

So ist die Situation weniger als ideal, aber wenn Sie die aufrufende Funktion in Javascript in allen gängigen Browsern zugreifen möchten, können Sie die Function.caller Eigenschaft verwenden, entweder direkt auf einer benannten Funktionsreferenz zugegriffen wird, oder aus einer anonymen Funktion über die arguments.callee Eigenschaft.

Es ist besser zu nutzen genannte Funktionen als arguments.callee:

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

ist besser als

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

Die benannte Funktion wird der Zugang zu ihrem Aufrufer durch die Anrufer Eigenschaft:

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

, die besser ist als

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

Die deprecation ist aufgrund der aktuellen ECMAScript Design-Prinzipien .

Nur eine Erweiterung. Der Wert von „diesen“ Änderungen während der Rekursion. Im folgende (modifizierte) Beispiel faktorielles bekommt die {foo: true}. Objekt

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

Fakultäts ersten Mal wird das Objekt genannt, aber dies ist für rekursive Aufrufe nicht wahr.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top