Javascript Variablen mit let

Javascript Variablen mit let statt var

Die Deklaration von Variablen mit let oder const hat das alte Schlüsselwort var abgelöst. Variablen, die mit let oder const deklariert werden, gelten nur innerhalb ihres Blocks, während der Gültigkeitsbereich von Variablen mit var nur auf Funktionen eingeschränkt ist. var ist zwar komfortabel, aber in großen Projekten schnell eine abgrundtiefe Fehlerquelle.

23-02-02 SITEMAP CSS HTML JS Basis JS Web Tutorial SVG

Variablen mit let statt var

Mit Javascript ES6 ist das Schlüsselwort let aufgetaucht. let ermöglicht eine neue Form des Abkapseln von Variablen und bringt eine Programmierpraxis, die es bislang in Javascript nicht gab: Block Scope – den Gültigkeitsbereich einer Variablen auf einen Block {} beschränken.

Bislang galt in Javascript nur die Beschränkung auf den Gültigkeitsbereich von Funktionen. Variablen, die mit var in einer Funktion angelegt werden, gelten nur innerhalb der Funktion. Das schützt Variablen vor versehentlichem Überschreiben.

Was ist aller Welt ist so schlimm an var, dass wir jetzt let vorziehen?

if-Abfragen: let vs var

Eine der klassischen Fallen hinter der Definition von Variablen mit var lauert innerhalb einer if-Abfrage.

var condition = false;
function foo(condition) {
   if (condition) {
      var a = 4; // Gültigkeitsbereich von a ist die Funktion foo
      let b = 5; // Gültigkeitsbereich von b ist der Block der if-Abfrage
   }
   
   var c = a + 17;
}

foo(condition);

Ist die Bedingung nicht erfüllt, ist a nach der if-Abfrage undefined und das Ergebnis von Berechnungen, die auf a aufbauen, liefert NaN. Das Skript läuft ohne Warnung munter weiter. Die mit let deklarierte Variable hingegen würde in jedem Fall nach der if-Abfrage zu einem sofort sichtbaren Syntaxfehler führen.

for let i=0

Obwohl der Scope oder Gültigkeitsbereich von var hier nicht auf den for-Block beschränkt ist, ist for (var i=0 … ) ein oft genutztes Muster.

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

Mit diesem Muster wollen Programmierer eine Variable nur für einen kleinen abgegrenzten Bereich definierten (und als solche kennzeichnen), auch wenn ihnen bewußt ist, dass var i »nach oben gehoben« wird und oberhalb des for-Blocks gilt. var i signalisiert, dass i tatsächlich nur innerhalb des for-Blocks benutzt werden soll.

Aber wer ist hierauf nicht schon einmal reingefallen?



			
var buttons = document.querySelectorAll("button");
for (var i=0; i<buttons.length; i++) {
    buttons[i].onclick = function() {
        console.log ("Button " + i);
    }
}

Egal welcher Button den Klick abbekommt, die Ausgabe liefert immer dasselbe letzte i der for-Anweisung. Das Event muss als Argument in der anonymen Funktion aufgeführt werden und der angeklickte Button in der Funktion mühsam durch das Event Target identifiziert werden.

Mit for (let i=0 … ) hingegen sagt i, welcher Button geklickt wurde.



			
let buttons = document.querySelectorAll("button");
for (let i=0; i<buttons.length; i++) {
    buttons[i].onclick = function() {
        console.log ("Button " + i);
    }
}

let-Variablen in for-loops werden automatisch getrennt an jede Iteration gebunden. Das gilt allerdings nicht für IE11. Im Großen und Ganzen unterstützt IE 11 zwar let, aber Variablen werden in IE11 nicht getrennt an jeden Durchlauf der for-Schleife gebunden.

Block-Scope

Vor ES6 haben Blöcke von geschweiften Klammern in Javascript keinen Scope gebildet. Scope ist die Bezeichnung für die Umgebung, in der eine Variable gilt. Den einzigen Scope bildeten bis ES5 Javascript-Funktionen. Darum sehen wir rund um den Quelltext von Libraries – z.B. jQuery – Self Executing Functions oder selbst ausführenden Funktionen.

(function () {
	// script code
} () );

Mit ECMAScript 6 sind Variablen, die mit let oder const definiert wurden, nur innerhalb ihres Blocks in geschweiften Klammern bekannt, und können außerhalb ihres Geltungsbereichs nicht durch Variablen mit demselben Namen überschrieben werden.

{ 
	let x = 1; 
	console.log(x); 
	{ 
		let x = 2; 
		console.log(x) 
	}; 
	console.log(x);
}
Ausgabe
1 2 1

Ob das immer gut lesbar ist, ist eine andere Frage … .

Hoisting oder Anheben

Anheben oder Hoisting bedeutet, dass Variablen automatisch im Hintergrund an den Anfang ihres Scopes gehoben werden, Funktionen automatisch vor ihren ersten Aufruf, damit sie beim Aufruf definiert sind.

// So steht's im Script
foo ();

function foo () {
   var bar = 2; 
   if (bar > 1 | midi) {
      bar nat = bar * 10;
   }
   var midi = (nat * 2) + 2;
   console.log (midi);
}
// So wirkt Hoisting
function foo () {
   var bar, midi, nat; 
   bar = 2;
   if (bar > 1 | midi) {
      bar nat = bar * 10;
   }
   midi = (nat * 2) + 2;
   console.log (midi);
}

foo ();

Mit ECMAScript 6 werden Variablen mit let nicht mehr automatisch an den Anfang des Blocks gehoben.

Wird eine Variable vor ihrer Definition angesprochen, gibt's einen ReferenceError. Bevor eine Variable definiert wird, liegt sie in einem temporalen schwarzen Loch.

var durch let ersetzen?

Wir können aber nicht gleich zur Suchen und Ersetzen-Funktion des Programm-Editors greifen und alle Vorkommen von var durch let ersetzen, denn dabei lauern fiese Fallen. Die vorangegangenen Beispiele zeigen bereits, dass der Unterschied zwischen let und var mehr mit sich bringt als den Block-Scope.

Kein Problem mit var
var a = 1;
if ( a > 0 ) {
    var panic = 42;
} else {
    var panic = "Immer ein Handtuch dabei haben";
}

console.log ( panic );

würde mit einer einfachen Ersetzung von var durch let einen Syntax-Fehler Can't find variable: panic liefern.

Das Ersetzen von var durch let bzw. const ist ein Prozess, erfordert erneute Tests und sollte in erster Linie dort ersetzt werden, wo es aus rein stilistischen Gründen eingesetzt wurde (z.B. in for (var i=0) – dabei aber IE11 im Hinterkopf behalten).

var muss auch nicht spurlos aus der Welt verschwinden, sondern kann als Stilmittel eingesetzt werden. let ist angebracht, wo ein eingeschränkter Block-Scope angebracht ist, var zeigt an, dass sich der Gültigkeitsbereich einer Variablen über die gesamte Funktion erstreckt.

function foo () {
	var midi = 42;
	… 
	if (midi > 33) {
		let a = midi * 10;
	}
}

Ah! var midi ist das Signal, dass midi in der gesamten Funktion benötigt wird. let a schafft einen Block-Scope für einen eingeschränkten Schauplatz des Geschehens.

Ein Stilmittel für diejenigen, die mit Function Scope und Block Scope bereits gut umgehen können.

Kein Polyfill für let?

Nein, es gibt kein Polyfill für let. Javascript Polyfills gibt es für Objekte und Methoden, nicht aber für neue Syntax-Elemente. Um let auch älteren Browsern zugänglich zu machen, muss ein Transpiler – babel.js – eingesetzt werden.

Immerhin ist Javascript const mehr als ein kleines Trostpflaster und wird auch von älteren Browsern erkannt (z.B. Safari iOS 9, Firefox 35 und älter, Opera Mini), wenn auch nicht unbedingt mit Blockscope und nicht im strict mode. Also wirklich nur ein ganz kleines Trostpflaster.