Diese Übersetzung ist unvollständig. Bitte helfen Sie, diesen Artikel aus dem Englischen zu übersetzen.
Die arguments.callee
-Eigenschaft enthält die Referenz der aktuell ausgeführten Funktion.
Beschreibung
callee
ist eine Eigenschaft des arguments
-Objektes. Sie kann eingesetzt werden, um aus dem Rumpf einer Funktion auf die aktuell ausgeführte Funktion zu referenzieren. Dieses ist sinnvoll, wenn der Name der Funktion unbekannt ist. Auch in einer anonymen Funktion (ohne Namen) funktioniert dieses.
arguments.callee() im
strict mode
. Der Einsatz von arguments.callee()
soll vermieden werden, wenn function-Ausdrücke einen Namen haben oder Funktionen deklariert werden, die sich selbst aufrufen müssen.Warum wurde arguments.callee
vom ES5 strict mode entfernt?
(angepasst von einer Stack Overflow-Antwort von olliej)
Frühe Versionen von JavaScript erlauben keine benamten Funktions-Anweisungen. Aus diesem Grund ist es nicht möglich rekursive Funktions-Anweisungen zu schreiben.
Diese Syntax funktioniert, zum Beispiel:
function factorial (n) { return !(n > 1) ? 1 : factorial(n - 1) * n; } [1,2,3,4,5].map(factorial);
aber:
[1,2,3,4,5].map(function (n) { return !(n > 1) ? 1 : /* what goes here? */ (n - 1) * n; });
funktioniert nicht. Um dieses problem zu lösen wurde arguments.callee
hinzugefügt.
[1,2,3,4,5].map(function (n) { return !(n > 1) ? 1 : arguments.callee(n - 1) * n; });
Allerdings ist dieses eine schlechte Lösung , weil diese (in Verbindung mit anderen arguments
, callee
, and caller
-Problemen) inlining und Endrekursion unmöglich macht (man kann es benutzen um tracing zu realisieren, jedoch ist der beste Code immer suboptimal). Ein weiteres Problem liegt darin, dass rekursieve Aufrufe ein unterschiedliches this bekommen können (siehe fogendes 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();
ECMAScript 3 löste das Problem indem benamte Funktions-Ausdrücke erlaubt wurden:
[1,2,3,4,5].map(function factorial (n) { return !(n > 1) ? 1 : factorial(n-1)*n; });
Dieses hat zahlreiche Vorteile:
- Die Funktion kann wie jede andere Funktion im Code aufgerufen werden.
- Es wird keine Variable im äußeren Gültigkeitsbereich erstellt (Ausnahme für IE 8 und kleiner)
- Es gibt eine bessere Performance wenn das arguments-Objekt genutzt wird
Eine andere Funktion die verboten wurde ist arguments.callee.caller
oder spezifischer Function.caller
. Warum ist das so? Zu jedem Zeitpunkt ist es möglich, den tiefsten Aufrufer von jeder Funktion auf dem Stack herauszufinden und weil das herausfinden des Aufrufer-Stacks hat einen hauptsächlichen Effekt: Es macht das Optimieren unmöglich oder sehr viel schwerer. Zum Beispiel ist es nicht Möglich f zu inlinen, wenn nicht sichergestellt ist, dass eine Funktion f nicht eine unbekannte funktion aufruft. Das bedeutet, dass jeder Aufruf eine große Anzahl an Sicherheitsabfragen durchführen müsste um inlinen zu können.
function f (a, b, c, d, e) { return a ? b * c : d * e; }
If the JavaScript interpreter cannot guarantee that all the provided arguments are numbers at the point that the call is made, it needs to either insert checks for all the arguments before the inlined code, or it cannot inline the function. Now in this particular case a smart interpreter should be able to rearrange the checks to be more optimal and not check any values that would not be used. However in many cases that's just not possible and therefore it becomes impossible to inline.
Examples
Using arguments.callee
in an anonymous recursive function
A recursive function must be able to refer to itself. Typically, a function refers to itself by its name. However, an anonymous function (which can be created by a function expression or the Function
constructor) does not have a name. Therefore if there is no accessible variable referring to it, the only way the function can refer to itself is by arguments.callee
.
The following example defines a function, which, in turn, defines and returns a factorial function. This example isn't very practical, and there are nearly no cases where the same result cannot be achieved with named function expressions.
function create() { return function(n) { if (n <= 1) return 1; return n * arguments.callee(n - 1); }; } var result = create()(5); // returns 120 (5 * 4 * 3 * 2 * 1)
A use of arguments.callee
with no good alternative
However, in a case like the following, there are not alternatives to arguments.callee
, so its deprecation could be a bug (see Bug 725398):
function createPerson (sIdentity) { var oPerson = new Function("alert(arguments.callee.identity);"); oPerson.identity = sIdentity; return oPerson; } var john = createPerson("John Smith"); john();
Specifications
Specification | Status | Comment |
---|---|---|
ECMAScript 3rd Edition. | Standard | Initial definition. Implemented in JavaScript 1.2 |
ECMAScript 5.1 (ECMA-262) Die Definition von 'Arguments Object' in dieser Spezifikation. |
Standard | |
ECMAScript 6 (ECMA-262) Die Definition von 'Arguments Exotic Objects' in dieser Spezifikation. |
Anwärter Empfehlung |
Browser compatibility
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Basic support | (Ja) | (Ja) | (Ja) | (Ja) | (Ja) |
Feature | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Basic support | (Ja) | (Ja) | (Ja) | (Ja) | (Ja) | (Ja) |