2

Ich lerne JavaScript, aber es gibt viele Dinge, die ich nicht verstehen kann. Bei einem Online-JavaScript-Quiz, erschien die folgende Frage:
Was wird das folgende JavaScript-Code Protokoll zu trösten:JavaScript: ORDER der Funktionsausführung

const a = {}; 
const b =() => a.a =() => {}; 
const c = c => '' + c + a.a(b()); 
const d = console.log.bind(console); 
const e = (e =>() => d(c(e++)))(0); 

try{ 
    e(); 
}catch(a){ 
    e(); 
} 

Es dauerte einige Zeit, um zu verstehen, was jede Variable (hier konstant) steht. Ich begann den Code aus dem e() innerhalb try Block zu analysieren. So stellt e eine Schließung dar, was bedeutet, dass die Funktion d mit dem Argument c(0) aufgerufen wird und e1 wird. Wie ich verstanden habe, hier d im Grunde repräsentiert die console.log Funktion (aber ich kann nicht herausfinden, warum haben sie bind verwendet?).

Für jetzt weiß ich, dass zuerst c(0) ausgeführt wird und dann Ergebnis an die Konsole, richtig? Werfen wir einen Blick auf die Funktion c. Es gibt das erste Argument in Zeichenfolge und verkettetes Ergebnis von a.a(b()) zurück. Ok, also a.a(b()) wird zuerst ausgeführt, habe ich recht? Aber das Problem ist, weil a.a keine Funktion ist, ist es undefiniert, so wird Fehler geworfen und wir gehen zu catch.

Jetzt, in catch Block sollte alles gleich sein, so a.a ist immer noch keine Funktion und Referenzfehler sollte geworfen werden. Aber es überraschte mich, als ich sah, dass kein Fehler ausgelöst wurde, aber die Konsole loggte sich tatsächlich 1undefined. Warum? Wie?

Ok, nach ein bisschen Nachdenken, habe ich festgestellt, dass vielleicht a.a(b()) vielleicht zuerst b() ausgeführt wird. Nach meiner Annahme, dann Funktion b Zuordnung Verweis auf eine Funktion, die nichts zur Eigenschaft a des Objekts a, Recht? Aber dann, a.a ist eine Funktion und es wird in try Block ausgeführt und 0undefined wird protokolliert werden.

Keine dieser beiden Annahmen ist jedoch korrekt. Die Hauptfrage hier ist, was zuerst ausgeführt wird? Wenn wir someObject.propertyWhichIsNotAFunction(somethingWhichMakesItAFunction) anrufen, was wird passieren? Was wird zuerst ausgeführt? Es scheint, dass in try Block eine Sache zuerst und in catch andere Sache ausgeführt wird. Es macht wirklich keinen Sinn für mich. Irgendwelche Erklärungen?

Antwort

1

Dies ist der Ursache von Why is the value of foo.x undefined in foo.x = foo = {n: 2}? sehr ähnlich, nur ein bisschen kniffliger, da es sich darauf verlässt, wenn ein TypeError in der Ausführung geworfen wird.

Im Grunde, was passiert ist:

  1. a.a ausgewertet, um herauszufinden, welche Funktion wird später in Schritt 3 aufgerufen werden.
  2. b() wird ausgewertet, da es ein Funktionsargument ist und sein Rückgabewert Wert wird das eigentliche Argument zu was auch immer a.a ausgewertet wird.
  3. Was auch immer a.a in Schritt 1 ausgewertet wird, wird mit dem Rückgabewert b() als Argument ausgeführt.

Der relevante Teil der Spezifikation ist hier: https://www.ecma-international.org/ecma-262/7.0/index.html#sec-function-calls

Beachten Sie, dass das erste, was passiert, wenn eine Funktion aufgerufen wird:

  1. Lassenref das Ergebnis sein Bewerten von MemberExpression.
  2. Lassen func sein? GetValue (ref).

Das bedeutet, dass a.a ausgewertet wird und die Funktion bezieht er sich auf sich func genannt. Das erste Mal, um a.a ausgewertet undefined, so func ist undefined und ein Typeerror wird in Schritt 2 von https://www.ecma-international.org/ecma-262/7.0/index.html#sec-evaluatedirectcall geworfen werden, was nachArgumentListEvaluation(arguments), den b() Anrufen und weist einen neuen Wert zu a.a, aber nicht nach der Wert von func.

+0

Was bedeutet, dass, wenn 'a.a' keine Funktion ist, unabhängig davon, was bei der Auswertung ihrer Argumente passiert, ein Referenzfehler ausgelöst werden muss (außer wenn die Auswertung selbst einen Fehler auslöst)? Nun, das ist ziemlich komisch. Ich dachte, JavaScript soll unnötige Berechnungen wie 'f1() && f2()' vermeiden, wenn 'f1()' zu false führt, dann wird 'f2()' nicht ausgeführt. Was ist die Logik, Argumente einer Funktionsreferenz zu bewerten, von der wir sicherlich wissen, dass wir sie nicht nennen können? –

+0

@ manga171 Argumente können Nebeneffekte haben, wie 'b()'. Die Spezifikation konzentriert sich mehr auf Korrektheit als auf Optimierung, und die Kurzschlußauswertung von 'f1() && f2()' kann auch Korrektheitsauswirkungen haben, zum Beispiel wird 'isReady() && go()' garantiert, 'go() nicht aufzurufen. 'if' isReady() 'return' false', gibt es keinen solchen Vorteil, dass Funktionsargumente vor dem Aufruf der Funktion nicht ausgewertet werden; Die umgekehrte Frage ist interessanter: Was ist die Logik der Auswertung der Funktionsreferenz vor der Auswertung der Argumente? – Paulpro

+0

@ manga171 Die Antwort darauf ist wahrscheinlich, dass die Spezifikation nicht perfekt ist und Änderungen, die den bestehenden Code betreffen, sind eine große Sache. Es ist leicht zu zeigen, dass 'ArgList sein soll? ArgumentListEvaluation (Arguments) .' passiert immer, so dass es möglich wäre, es aus irgendwelchen Bedingungen herauszuziehen und es als erstes zu machen, was passiert, wenn eine Funktion ausgewertet wird, aber es würde das Verhalten des Codes in Ihrer Frage verändern niemals eine Ausnahme werfen; Ich denke, es würde "0undefined" ausgeben. – Paulpro

Verwandte Themen