var, let und const - Was ist der Unterschied?

Geltungsbereich von Variablen in Javascript

Mit der im Juni 2015 erschienen Version ECMAScript 2015 (ES6 oder ECMAScript 6) kamen einige tolle neue Features.
Neu sind let und const, die für das Deklarieren von Variablen genutzt werden können. Nun ist die Frage, was sie von dem guten alten var unterscheidet.

In diesem kurzen Artikel werde ich var, let und const in Bezug auf ihren Geltungsbereich (scope) und ihre Verwendung behandeln.

var

Vor dem Erscheinen von ES6 wurden Variablen lediglich mit var deklariert. Dieser Weg führt jedoch oft zu Problemen, die vor allem bei Programmen mit langem Code, an dem dann vielleicht noch mehrere Personen arbeiten, auftreten. Aus diesem Grund war es notwendig, neue Varianten zur Deklaration von Variablen zu entwickeln. Lasst uns zuerst var besser verstehen, bevor wir diese Probleme diskutieren.

Geltungsbereich (scope) mit var

Geltungsbereich oder scope bedeutet im Wesentlichen, wo diese Variablen zur Verwendung verfügbar sind. Deklarationen mit var sind global oder funktions-begrenzt. Der Geltungsbereich ist global (global scope), wenn eine Variable mit var außerhalb einer Funktion deklariert wird. Das bedeutet, dass jede Variable, die außerhalb eines Funktionsblocks mit var deklariert ist, im gesamten JavaScript Programm zur Verfügung steht. var ist funktionsbezogen (function scope), wenn es innerhalb einer Funktion deklariert wird. Dies bedeutet, dass es nur innerhalb dieser Funktion verfügbar ist und nicht außerhalb der Funktion darauf zugegriffen werden kann.

Beispiel:


var foo = 'Lorem ipsum';

function myFunction() {
    var bar = 'Dolor sit amet';
}

console.log(bar); // Uncaught ReferenceError: bar is not defined

Wir bekommen also eine Fehlermeldung, da die Variable bar nicht ausserhalb der Funktion myFunction vorhanden ist.

Die Variable foo hat hier einen global scope, weil sie außerhalb einer Funktion deklariert wurde. Die Variable bar hingegen hat einen function scope. Wir können sie nicht außerhalb der Funktion myFunction nutzen.

Variablen, die mit var deklariert wurden, können neu deklariert und aktualisiert werden

Dies bedeutet, dass wir folgendes im selben scope tun können ohne einen Fehler zu erhalten:


var foo = 'Lorem ipsum';
var foo = 'Dolor sit amet';

Und dies funktioniert ebenfalls:


var foo = 'Lorem ipsum';
foo = 'Dolor sit amet';

Hoisting im Zusammenhang mit var

In JavaScript können Variablen genutzt werden, bevor sie deklariert wurden. Variablen- und Funktionsdeklarationen werden dann vor der Ausführung des Codes an den Anfang ihres Gültigkeitsbereiches verschoben. Dies wird Hoisting genannt.

Folgende zwei Beispiele haben das selbe Ergebnis:


foo = 14;
console.log(foo);

var foo;


var foo;
foo = 14;
console.log(foo);

An folgendem Beispiel können wird sehen, dass mit var deklarierte Variablen an den Anfang verschoben und mit dem Wert undefined initialisiert werden.


console.log(foo);
var foo = 'bar';

Wir erhalten nicht die Fehlermeldung ReferenceError: foo is not defined, sondern es wird undefined ausgegeben.

Das Problem mit var

Es gibt ein Problem mit var, welches im folgenden Beispiel veranschaulicht werden soll:


var foo = 'bar';
var bar = 7;

if (bar > 2) {
    var foo = 'baz';
}

console.log(foo); // 'baz'

Weil die Variable bar hier größer als 2 ist, wird die Variable foo neu definiert. Dies ist zwar kein Problem, wenn man wissentlich möchte, dass foo neu definiert wird, aber es wird zu einem Problem, wenn man nicht erkennt, dass bereits zuvor eine Variable foo definiert wurde und jetzt in ihrem scope überschrieben wird.

Wenn du die Variable foo bereits in anderen Teilen deines Codes verwendet hast, wirst du möglicherweise von der Ausgabe überrascht sein, die du erhältst. Dies kann zu Fehlern im Code führen, vor allem, wenn dieser lang und verschachtelt ist oder mehrere Personen an dem selben Projekt arbeiten. Aus diesem Grund sind let und const mit ES6 neu hinzugekommen.

let

let wird nun für die Deklaration von Variablen bevorzugt genutzt. Es löst das Problem von var, welches wir gerade behandelt haben. Warum, sehen wir im Folgenden:

let ist block scoped

Ein Block is ein Teil des Codes, welcher duch {} vom Rest abgegrenzt ist. Alles innerhalb geschweifter Klammern ist ein Block.

Eine in einem Block mit let deklarierte Variable ist also nur für die Verwendung innerhalb dieses Blocks verfügbar. Hierzu ein Beispiel:


let foo = 'Lorem ipsum';
let bar = 4;

if (bar > 2) {
    let baz = 'Dolor sit amet';
    console.log(baz); // "Dolor sit amet"
}
console.log(baz); // Uncaught ReferenceError: baz is not defined

Wir sehen also, dass wir baz nicht außerhalb seines Blocks nutzen können, sondern uns ein Fehler ausgegeben wird. Der Grund dafür ist, dass mit let deklarierte Variablen einen sogenannten block scope haben.

Variablen, die mit let deklariert wurden, können aktualisiert aber nicht neu deklariert werden

Genau wie var kann eine mit let deklarierte Variable innerhalb ihres scopes aktualisert werden. Im Gegensatz zu var kann eine mit let deklarierte Variable jedoch nicht innerhalb ihres scopes erneut deklariert werden.

Folgendes funktioniert:


let foo = 'Lorem ipsum';
foo = 'Dolor sit amet';

Wohingegen hier ein Fehler auftritt:


let foo = 'Lorem ipsum';
let foo = 'Dolor sit amet'; // Uncaught SyntaxError: Identifier 'foo' has already been declared

Wenn jedoch die selbe Variable in verschiedenen scopes definiert wird, tritt kein Fehler auf:


let foo = 'Lorem ipsum';
let bar = 4;

if (bar > 2) {
    let foo = 'Dolor sit amet';
    console.log(foo); // "Dolor sit amet"
}
console.log(foo); // "Lorem ipsum"

Warum gibt es hier keinen Fehler? Dies liegt daran, dass beide Instanzen foo als unterschiedliche Variablen behandelt werden, da sie unterschiedliche Gültigkeitsbereiche (scopes) haben.

Diese Tatsache macht let zu einer besseren Wahl als var. Wenn man let verwendet, muss man sich nicht darum kümmern, ob man zuvor einen Namen für eine Variable verwendet hat, da eine Variable nur innerhalb ihres scopes existiert.

Zusätzlich ist es von Vorteil, dass eine Variable, die mit let deklariert wurde, nicht mehr als einmal deklariert werden kann.

Hoisting im Zusammenhang mit let

Genau wie var werden Deklarationen bei let an den Anfang ihres Gültigkeitsbereiches verschoben (Hoisting). Im Gegensatz zu var, das Variablen als undefiniert initialisiert, wird die Variable bei let jedoch nicht initialisiert. Wenn man also versuchen, eine Variable, die mit let deklariert wurde, vor der Deklaration zu verwenden, erhält man eine Fehlermeldung.

const

Variablen, die mit const deklariert wurden, behalten konstante Werte bei. const-Deklarationen haben einige Ähnlichkeiten mit let-Deklarationen.

const ist block scoped

Genau wie bei let kann auf Variablen, die mit const deklariert wurden, nur innerhalb ihres Blocks zugegriffen werden.

Variablen, die mit const deklariert wurden, können weder aktualisiert noch neu deklariert werden

Das bedeutet, dass der Wert einer mit const deklarierten Variablen innerhalb ihres scopes gleich bleibt. Er kann nicht aktualisiert oder neu deklariert werden. Folgendes ist also nicht möglich:


const foo = 'Lorem ipsum';
foo = 'Dolor sit amet'; // Uncaught TypeError: Assignment to constant variable

Eine Neudeklaration ist ebenfalls nicht möglich:


const foo = 'Lorem ipsum';
const foo = 'Dolor sit amet'; // Uncaught SyntaxError: Identifier 'foo' has already been declared

Jede Deklaration von Variablen mit const muss daher zum Zeitpunkt der Deklaration initialisiert werden.

Das Verhalten ist jedoch etwas anders, wenn es um mit const deklarierte Objekte geht. Während ein konstantes Objekt nicht aktualisiert werden kann, können die Eigenschaften dieses Objekts jedoch wohl aktualisiert werden. Wenn wir also ein konstantes Objekt wie folgt deklarieren:


const foo = {
    bar: 'Lorem ipsum',
    baz: 14
}

Können wir folgendes nicht tun:


foo = {
    bar: 'Dolor sit amet',
    baz: 'consetetur sadipscing elitr'
}

// Uncaught TypeError: Assignment to constant variable

Dies ist jedoch möglich:


foo.bar = 'consetetur sadipscing elitr';

Der Wert von foo.bar wird aktualisiert, ohne das ein Fehler auftritt.

Hoisting im Zusammenhang mit const

Genau wie bei let werden Variablen, die mit const deklariert wurden, nach oben gehoben, aber nicht initialisiert.

Zusammenfassung

  • Mit var deklarierte Variablen haben einen globalen oder funktioinsbezogenen scope, wohingegen mit let oder const deklarierte Variablen einen blockbezogenen scope haben.
  • var-Variablen können innerhalb ihres scopes aktualisiert und neu deklariert werden; let-Variablen können aktualisiert, aber nicht neu deklariert werden; const-Variablen können weder aktualisiert noch neu deklariert werden.
  • In allen drei Fällen, wird die Deklaration an den Anfang des Gültigkeitsbereiches verschoben. Aber während var-Variablen mit undefined initialisiert werden, werden let- und const-Variablen nicht initialisiert.
  • Während Variablen mit var und let ohne Initialisierung deklariert werden können, muss eine Variable mit const während der Deklaration initialisiert werden.