JavaScript-Variablen deklarieren außerhalb oder innerhalb der Schleife?


212

In AS3 sollten Sie meiner Meinung nach alle Variablen außerhalb von Schleifen initialisieren, um die Leistung zu steigern. Ist dies auch bei JavaScript der Fall? Was ist besser / schneller / Best Practice?

var value = 0;

for (var i = 0; i < 100; i++)
{
    value = somearray[i];
}

oder

for (var i = 0 ; i < 100; i++)
{
    var value = somearray[i];
}

7
Draußen! immer draußen.
BGerrissen

37
Hmm, werden Variablendeklarationen nicht trotzdem in Javascript und AS3 in den Funktionsumfang verschoben? Wenn ich richtig liege, ist das wirklich egal.
Spender

3
@Andy - haben Sie versucht, zuzuweisen, bevor Sie in einem Funktionskörper deklariert haben? Vielleicht führen Sie Ihre Vorurteile in die Irre. WRT-Leistung mit Push-up-Scoping: Wenn der JS interpretiert wird, werden zusätzliche Zyklen innerhalb eines Schleifenblocks gekaut. Wenn kompiliert (was die meisten Motoren heutzutage tun), spielt es keine Rolle.
Spender

2
Gute Frage! Vielen Dank. Nachdem ich alle Antworten gelesen habe, glaube ich, wenn es nur eine kleine Schleife oder nur eine temporäre Variable ist, werde ich sie dort belassen, wo sie benötigt werden, und es hat keinen Einfluss auf die Leistung. Wenn eine Variable innerhalb einer Funktion mehr als einmal verwendet wird, warum nicht innerhalb der Funktion auf sie verweisen und schließlich global, dann kann sie außerhalb des fn () sitzen
Dean Meehan

3
Ich bin überrascht, dass niemand versucht hat, die Leistung zu messen. Ich habe ein jsperf erstellt . Scheint etwas schneller zu sein, wenn es innerhalb der Schleife für Safari und Firefox deklariert wird, das Gegenteil für Chrome…
Buzut

Antworten:


281

Es gibt absolut keinen Unterschied in der Bedeutung oder Leistung in JavaScript oder ActionScript.

varist eine Direktive für den Parser und kein zur Laufzeit ausgeführter Befehl. Wenn ein bestimmter Bezeichner varan einer beliebigen Stelle in einem Funktionskörper (*) einmal oder mehrmals deklariert wurde , bezieht sich jede Verwendung dieses Bezeichners im Block auf die lokale Variable. Es spielt keine Rolle, ob innerhalb der Schleife, außerhalb der Schleife oder beides valuedeklariert ist var.

Folglich sollten Sie schreiben, was Sie am besten lesbar finden. Ich bin mit Crockford nicht einverstanden, dass es immer das Beste ist, alle Vars an die Spitze einer Funktion zu setzen. Für den Fall, dass eine Variable vorübergehend in einem Codeabschnitt verwendet wird, ist es besser, varin diesem Abschnitt zu deklarieren , damit der Abschnitt eigenständig ist und kopiert werden kann. Andernfalls kopieren Sie während des Refactorings einige Codezeilen in eine neue Funktion, ohne die zugehörigen Elemente separat auszuwählen und zu verschieben var, und Sie haben einen versehentlichen globalen Fehler.

Bestimmtes:

for (var i; i<100; i++)
    do something;

for (var i; i<100; i++)
    do something else;

Crockford wird Ihnen empfehlen, das zweite zu entfernen var(oder beide vars zu entfernen und var i;oben zu tun ), und jslint wird Sie dafür beschimpfen. Aber IMO ist es wartbarer, beide zu behaltenvar s und den gesamten zugehörigen Code zusammenzuhalten, anstatt ein zusätzliches, leicht vergessenes Stück Code oben in der Funktion zu haben.

Persönlich neige ich dazu, als varerste Zuweisung einer Variablen in einem unabhängigen Codeabschnitt zu deklarieren , ob es in einem anderen Teil derselben Funktion eine andere separate Verwendung desselben Variablennamens gibt oder nicht. Für mich varist es eine unerwünschte JS-Warze , überhaupt deklarieren zu müssen (es wäre besser gewesen, wenn die Variablen standardmäßig lokal wären). Ich sehe es nicht als meine Pflicht an, die Einschränkungen von [einer alten Revision von] ANSI C auch in JavaScript zu duplizieren.

(*: außer in verschachtelten Funktionskörpern)


4
Ich kann mich immer noch nicht entscheiden, ob ich mit Crockford zusammen bin oder nicht. Das Deklarieren von Variablen innerhalb von Blöcken fühlt sich ein bisschen wie das Verwenden von bedingten Funktionsanweisungen an (was ungezogen ist) ... Ich stimme jedoch auch Ihren Punkten zu :) #confused
Daniel Vassallo

20
+1 Ich bin nicht einverstanden mit Crockfords Argumentation (zitiert in Daniels Antwort), da wir als JavaScript-Entwickler keinen Code schreiben sollten, damit andere Programmierer der "C-Familie" ihn verstehen können. Ich benutze oft var inside wenn Blöcke und Schleifen, weil es für mich sinnvoller ist.
Andy E

4
-1 Das OP fragt, ob vars im Hauptteil der Schleife deklariert werden sollen, bevor die Schleife beginnt. Der Indexwert der Schleife ist eindeutig ein Sonderfall (und wird angehoben) und hilft dem OP überhaupt nicht.
Mkoistinen

21
Schleifenindizes sind kein Sonderfall, sie werden genauso behandelt und gehisst wie normale Zuweisungen.
Bobince

31
+1 Crockford ist in dieser Sache falsch (und in anderen, aber ich schweife ab). Das Erfordernis, vardas nur am Anfang einer Funktion verwendet wird, fordert nur die versehentliche Erstellung globaler Variablen. Und eine Masse von nicht verwandten Variablen, die alle an einer Stelle deklariert sind, ist semantisch bedeutungslos, insbesondere wenn einige dieser Variablen möglicherweise nie verwendet werden.
MooGoo

64

Theoretisch sollte es in JavaScript keinen Unterschied machen, da die Sprache keinen Blockbereich hat, sondern nur einen Funktionsbereich.

Ich bin mir über das Leistungsargument nicht sicher, aber Douglas Crockford empfiehlt weiterhin, dass die varAnweisungen die ersten Anweisungen im Funktionskörper sein sollten. Zitieren aus Code-Konventionen für die JavaScript-Programmiersprache :

JavaScript hat keinen Blockbereich, daher kann das Definieren von Variablen in Blöcken Programmierer verwirren, die Erfahrung mit anderen Sprachen der C-Familie haben. Definieren Sie alle Variablen oben in der Funktion.

Ich denke, er hat einen Punkt, wie Sie im folgenden Beispiel sehen können. Das Deklarieren der Variablen am oberen Rand der Funktion sollte den Leser nicht verwirren, zu glauben, dass die Variable i im Bereich des forSchleifenblocks enthalten ist:

function myFunction() {
  var i;    // the scope of the variables is very clear

  for (i = 0; i < 10; i++) {
    // ...
  }
}

8
+1, um OP-Wahrheiten über den JS-Bereich zu sagen. Ich frage mich, ob ich Antworten, die etwas anderes aussagen, ablehnen soll!
Spender

1
@Kieranmaine: Ich habe nicht gesagt, dass es die Leistung nicht beeinflusst. Ich habe gerade ein Argument dafür vorgebracht, sie außerhalb der Schleifen zu platzieren, unabhängig von der Leistung ... Ich habe keine Referenzen für die Leistungsargumente, aber Sie haben auch keine in Ihrer Antwort zitiert :)
Daniel Vassallo

1
@Kieranmaine: hast du eine Quelle dafür?
Andy E

5
@Kieranmaine: AFAIK erhöht ecma- / javascriptdiese zur Laufzeit, selbst wenn Sie Variablen innerhalb einer Schleife deklarieren . Das nennt man "Heben". Es sollte also keinen Unterschied geben.
jAndy

1
Wie wirkt sich ES6 letauf diese Antwort aus?
2.

58

Die ECMA-/JavascriptSprache hoistsjeder Variablen, die irgendwo oben in einer Funktion deklariert wird. Das ist , weil diese Sprache nicht haben function scopeund sich nicht haben block scopewie viele andere C-ähnliche Sprachen.
Das ist auch bekannt als lexical scope.

Wenn Sie so etwas deklarieren

var foo = function(){
    for(var i = 0; i < 10; i++){
    }
};

Das kommt hoistedzu:

var foo = function(){
    var i;
    for(i = 0; i < 10; i++){
    }
}

Es macht also keinen Unterschied in der Leistung (aber korrigiere mich, wenn ich hier völlig falsch liege).
Ein viel besseres Argument dafür , eine Variable nicht an einer anderen Stelle als am Anfang einer Funktion zu deklarieren, ist die Lesbarkeit . Das Deklarieren einer Variablen innerhalb von for-loopkann zu der falschen Annahme führen, dass auf diese Variable nur innerhalb des Schleifenkörpers zugegriffen werden kann, was völlig falsch ist . Tatsächlich können Sie auf diese Variable überall im aktuellen Bereich zugreifen.


Gleiche grundlegende Antwort wie die akzeptierte, aber IMO, lesbarer und genauso informativ. Gut gemacht.
Anne Gunn

5
Wie wirkt sich ES6 letauf diese Antwort aus?
2.

13

Nächstes Jahr werden alle Browser über JS-Engines verfügen, die den Code vorkompilieren, sodass der Leistungsunterschied (der sich aus dem wiederholten Parsen desselben Codeblocks und dem Ausführen der Zuweisung ergibt) vernachlässigbar werden sollte.

Optimieren Sie niemals die Leistung, es sei denn, Sie müssen. Wenn Sie Variablen beim ersten Mal in der Nähe des Ortes halten, an dem Sie sie benötigen, bleibt Ihr Code sauber. Auf der negativen Seite können Personen, die an Sprachen mit Blockbereichen gewöhnt sind, verwirrt sein.


6

Eine weitere Überlegung, die wir jetzt letund constin ES2015 haben, ist, dass Sie jetzt Variablen speziell für den Schleifenblock festlegen können. Wenn Sie also nicht dieselbe Variable außerhalb der Schleife benötigen (oder wenn jede Iteration von einer Operation abhängt, die mit dieser Variablen in der vorherigen Iteration ausgeführt wurde), ist dies wahrscheinlich vorzuziehen:

for (let i = 0; i < 100; i++) {
    let value = somearray[i];
    //do something with `value`
}

4

Ich habe gerade einen einfachen Test in Chrome durchgeführt. Probieren Sie die Geige in Ihrem Browser aus und sehen Sie die Ergebnisse

  var count = 100000000;
    var a = 0;
    console.log(new Date());

    for (var i=0; i<count; i++) {
      a = a + 1
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
      a = a + 1;
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
        var x;
        x = x + 1;
    }

    console.log(new Date());

Das Ergebnis ist, dass der letzte Test ~ 8 Sekunden dauert und die vorherigen 2 nur ~ 2 Sekunden sind. Sehr wiederholbar und unabhängig von der Reihenfolge.

Das beweist mir also, dass man die Vars immer außerhalb der Schleife deklarieren sollte. Ein merkwürdiger Fall für mich ist der erste, den ich iin der for () - Anweisung deklariere . Dieser scheint genauso schnell zu sein wie der zweite Test, bei dem ich den Index vordeklariere.


14
@KP: Ergebnisse werden nur bewiesen, wenn Sie sie selbst testen oder wenn eine große Anzahl von Personen sie überprüft. @mkoistinen: Ich habe einen faireren Test erstellt, jsfiddle.net/GM8nk . Nachdem ich das Skript mehrmals in Chrome 5 ausgeführt hatte, konnte ich feststellen, dass es keinen konsistenten Gewinner gab. Alle drei Variationen zeigten nach einigen Aktualisierungen eine bessere Leistung als die anderen. -1 von mir, ich fürchte. Beachten Sie , möchten Sie vielleicht laufen diese ein in anderen Browsern. IE und Fx mochten keine 100 Millionen Iterationen.
Andy E

1
@ AndyE. Wow, also basierend auf diesem einfachen Test saugt IE 100X mehr? =)
mkoistinen

2
Die Ergebnisse sind für mich allgegenwärtig, kein klarer Cross-Browser-Gewinner, obwohl es manchmal erhebliche Geschwindigkeitsunterschiede gibt. Seltsam. Ich denke, Andys Geige ist jedoch ein besserer Test, bei dem jeder Kandidat in seine eigene Funktion versetzt wird. Wenn das ursprüngliche Skript außerhalb einer Funktion ausgeführt wird, sollte es eigentlich nichts testen, da die varVariable als global deklariert wird sei sowieso global.
Bobince

4
Über ein Jahr nach der Tatsache, aber SHAPOW
sdleihssirhc

2
Dies ist nicht meins, aber ich dachte, einige von Ihnen wären interessiert: jsperf.com/var-in-for-loop
m1.

1

JavaScript ist eine Sprache, die unten von C oder C ++ geschrieben wurde. Ich bin mir nicht sicher, welche es ist. Und einer seiner Zwecke ist es, den Aufwand für den Umgang mit internem Speicher zu sparen. Selbst in C oder C ++ müssen Sie sich keine Gedanken darüber machen, ob es viele Ressourcen verbraucht, wenn Variablen in einer Schleife deklariert werden. Warum sollten Sie sich in JavaScript darum kümmern?


1
C oder C ++ befinden sich möglicherweise am Ende von JavaScript. Wir sollten jedoch nicht vergessen, dass der Browser JavaScript in die zugrunde liegende Sprache (C, C ++) konvertiert. Die Leistung hängt also vom Browser ab
Kira

3
@Kira Es wird nicht wirklich in C / C ++ konvertiert. Javascript wird in eine Reihe von Anweisungen kompiliert, die von der JS-Laufzeit ausgeführt werden (dh eine virtuelle Maschine, die im Browser ausgeführt wird). Das gleiche Prinzip gilt für andere dynamische Sprachen wie Python und Ruby.
Anthony E

@AnthonyE, Danke für die Info. Ich war mir nicht sicher, ob JS nach C oder C ++ konvertieren sollte. Also habe ich vielleicht in meinem Kommentar verwendet
Kira

0

Nun, das hängt davon ab, was Sie erreichen möchten. Wenn Sie valueannehmen, dass es sich nur um eine temporäre Variable innerhalb des Schleifenblocks handelt, ist es viel klarer, die zweite Form zu verwenden. Es ist auch logischer und ausführlicher.


Ich habe festgestellt, dass das Verschieben aller Deklarationen von Variablen nach oben - einschließlich temporärer Variablen - tatsächlich zu Verwirrung führen kann, da es nur "laut" wird.
Daniel Sokolowski

0

Es macht keinen Unterschied, ob Sie Variablen innerhalb oder außerhalb der for-Schleife deklarieren. Unten finden Sie den zu testenden Beispielcode.

function a() {
   console.log('Function a() starts');
   console.log(new Date());
    var j;
    for (j=0; j<100000000; j++) {
        var x;
        x = x + 1;
    }
    console.log(new Date());
    console.log('Function a() Ends');
}
a()
function b() {
console.log('Function B() starts');
   console.log(new Date());
    var a;
    var j;
    for (j=0; j<100000000; j++) {
      a = a + 1;
    }
    console.log(new Date());
    console.log('Function B() Ends');
}
b()

Die Ergebnisse zeigten sich in meinem Fall

Function a() starts
VM121:3 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:9 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:10 Function a() Ends
VM121:14 Function B() starts
VM121:15 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:21 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:22 Function B() Ends

Vielen Dank - MyFavs.in


In beiden Fällen deklarieren Sie j außerhalb der Schleife! X_x
John Ktejik

Ich habe es in Chromium 81 mit letstatt versucht varund a()neige dazu, etwas langsamer zu sein (wie 120 vs 115 ms = ~ 6% = IMO unbedeutend)
mikiqex

-1

Die Frage hier ist im Grunde, eine var innerhalb einer Schleife zu deklarieren. Denken Sie nur daran, was passiert, wenn Sie dies tun:

var a = 30;
var a = 50;
var a = 60;

Glaubst du, das ist richtig? Nein ... weil Sie eine Variable nicht so oft deklarieren möchten. Wenn Sie eine Variable innerhalb einer Schleife deklarieren, deklariert sie dann nicht so oft, wie die Schleife ausgeführt wird? Offensichtlich wird es Sie schlagen, wenn Sie sich im Modus "Streng verwenden" befinden. Die Leute haben Crockford nicht zugestimmt, ohne über die ursprüngliche Frage nachzudenken.

Es ist also immer gut, Variablen oben zu deklarieren - 1. Zur besseren Lesbarkeit, 2. gute Gewohnheiten zu entwickeln.


1
"Wenn Sie eine Variable innerhalb einer Schleife deklarieren, deklariert sie dann nicht so oft, wie die Schleife ausgeführt wird?" <- Nein, das stimmt nicht. Die Variablendeklaration wird gehisst, sodass Sie nur noch eine Zuweisung haben.
Matthias

-2

In Bezug auf die Leistung nach dem Ausführen von Tests unter Chrome, Firefox und jsperf unter einem Linux-Betriebssystem scheint es einen Leistungsunterschied zwischen der Deklaration von Variablen in einer Schleife und außerhalb einer Schleife zu geben. Es ist ein kleiner Unterschied, aber dies wird auch durch die Anzahl der Iterationen und die Anzahl der Variablendeklarationen verstärkt.

Für eine optimale Leistung müsste ich daher vorschlagen, Variablen außerhalb der Schleife zu deklarieren. Oder deklarieren Sie Ihre Variablen noch besser in einer Zeile. Siehe Beispiel.

// inline
for (var ai = 0, al = 100000000, av; ai < al; ai++) {
    av = av + 1;
}

// outside
var bv;
var bl = 100000000;
for (var bi = 0; bi < bl; bi++) {
    bv = bv + 1;
}

Beachten Sie, wie sich die Variablen 'al' und 'av' in der for-Schleifendeklarationszeile befinden. Diese Inline-Erklärung hat mir eine durchweg bessere Leistung gebracht. Auch über die Deklaration von Variablen außerhalb der Schleife. Auch hier ist der Leistungsunterschied sehr gering.

https://jsperf.com/outside-inline-for-loop-ase/1


Für mich gab Ihr Test innerhalb der Schleife. Und wie auch immer, der Unterschied ist zu gering, um daraus zu schließen, und die akzeptierte Antwort erklärt deutlich, dass es keinen Unterschied gibt
Ulysse BN

Da Variablendeklarationen hochgezogen werden, gibt es wirklich keinen Unterschied.
Trincot
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.