Dass das alte Testament der modernen JavaScript-Community den Titel JavaScript: The Good Parts trägt, lässt erahnen, dass nicht alles in dieser Programmiersprache ganz problemfrei ist, also auch einiges an bad parts vorhanden ist. Diese werden von geübten Programmieren meist gemieden, stellen aber immer noch eine veritable Tretmine dar. Um diese problematischen „Features“ langsam gen Altenteil zu schieben, führt ES5 den Strict Mode ein, der eigentlich nichts weiter als ein Subset von „normalem“ JavaScript ist – alles Gute bleibt drin, alles Böse existiert im Strict Mode nicht mehr. Und wer weiter böse programmieren will, muss sich nicht fürchten, denn der Strict Mode ist ein Opt-In-Feature.

Was macht der Strict Mode?

Der Strict Mode ist ein bereinigtes JavaScript-Subset. Er führt nichts neues ein, entfernt aber einige problemtische Altlasten. Unter anderem wird

  • das unberechenbare with-Statement abgeschafft,
  • ein Fehler ausgelöst wenn man durch ein vergessenes var unbeabsichtigt eine globale Variable anlegt,
  • die Anzahl der befremdlichen Eigenheiten von this, eval() und arguments reduziert,
  • durch unsinnige Anweisungen wie NaN = 42 ein Fehler ausgelöst
  • und die oktale Syntax (0644 == 420) verboten.

JavaScript wird im Strict Mode also entrümpelt und vieles, was früher nur bad practice war, in einen handfesten Fehler, den ein Browser auch meldet. Es ist im Strict Mode einfach wesentlich schwieriger, schlechte Programme zu scheiben: Fehler werden sichtbarerer, die Quellen für solche Fehler werden weniger und der Programmierer kann sich mehr auf seine Aufgabe als auf die Besonderheiten seiner Programmiersprache konzentrieren.

Den Strict Mode auslösen

Strict Mode auszulösen ist einfach; man braucht nur "use strict"; an den Anfang einer Scriptdatei zu setzen:

"use strict";
x = "foo"; // ReferenceError - "var" vergessen

Das Ganze funktioniert auch auf Funktionsebene. Wer nicht komplette Scripts in den Strict Mode versetzen will, kann sich auf einzelne Funktionen beschränken:

var x = "Ich bin NICHT im Strict Mode!";

function foo(){
    "use strict";
    var y = "Ich BIN im Strict Mode!";
}

function bar(){
    var z = "Ich bin NICHT im Strict Mode!";
}

Der Strict Mode ist an den Funktionskontext gebunden. So wie innerhalb einer Funktion erstellte Funktionen auf die Variablen der äußeren Funktion Zugriff haben, so erben sie auch den Strict Mode:

var x = "Ich bin NICHT im Strict Mode!";

function foo(){
    "use strict";
    var y = "Ich BIN im Strict Mode!";
    return function(){
        var z = "Ich bin AUCH im Strict Mode!";
    }
}

Zu beachten ist, dass man den Strict Mode nicht auf einzelne If- oder Schleifen-Blöcke beschränken kann. Das Ganze funktioniert nur auf Script- oder Funktionsebene.

Strict-Mode-Scripts sind zu 100% abwärtskompatibel. Da für Browser, die den Strict Mode nicht kennen, "use strict"; nur ein beliebiger String, also ein JavaScript-Ausdruck ohne Bedeutung ist, verarbeitet auch der älteste Internet Explorer solche Scripts ohne zu murren – der Strict Mode definiert schließlich nichts weiter als ein Subset von „normalem“ JavaScript. Man kann also (theoretisch) ohne Probleme ab heute dazu übergehen, nur noch im Strict Mode zu programmieren, vorausgesetzt man testet seine Scripts vorher in mindestens einem Browser, der dieses ES5-Feature auch implementiert.

Die Auswirkungen des Strict Mode im Detail

Weniger globale Variablen: Erstellt man in normalem JavaScript eine neue Variable, ohne ihr var voranzustellen, macht man sie zu einer globalen Variable. Da dieser Effekt fast nie so gewollt ist (wer globale Variablen braucht, sollte sie auf der globalen Ebene mit var entsprechend deklarieren) und meist auf ein Vergessen des var zurückzuführen ist, hagelt es hierfür im Strict Mode Fehler. So kann man sich sicher sein, dass wenn am Ende des Tages das Programm keine Fehler wirft, man nirgends ein var vergessen hat.

"use strict";
x = 42; // ReferenceError - "var" fehlt

Mehr (sichtbare) Fehler: Es gibt in JavaScript viele Dinge, die man zwar ausdrücken kann, die aber nicht funktionieren. Es ist absolut möglich undefined = 42 in ein Script zu schreiben, doch einen Effekt hätte es (zum Glück) nicht – undefined ist (in ES5) schreibgeschützt. Damit man es aber auch mitbekommt, wenn man solcherlei Unsinn schreibt, wirft JavaScript im Strict Mode immer dort einen Fehler, wo es vorher nur stillschweigendes Nichtfunktionieren gab:

"use strict";
undefined = 42;          // TypeError - "undefined" kann nur undefined sein
delete Object.prototype; // TypeError - Object.prototype ist schreibgeschützt

Mehr Einzigartigkeit: Verwendet man in einer Funktion mehrere Argumente mit gleichem Namen oder versucht man, in einem Objektliteral mehrere gleichnamige Eigenschaften zu definieren, setzt es im Strict Mode einen Syntaxfehler. Nur so bemerkt man solche einfache Fehler sofort beim ersten Test, denn ohne Strict Mode würde einfach das jeweils letzte Argument bzw. die letzte Objekteigenschaft stillschweigend ihre Vorgänger überschreiben. Und so etwas zu debuggen kann richtig schwierig werden – schwieriger jedenfalls, als einfach die Syntaxfehler im Strict Mode zu finden und auszumerzen.

"use strict";
var o = { foo: "x", foo: "y" }; // SyntaxError - Zwei mal "foo" geht nicht
function foo(x, x, z){}         // SyntaxError - Zwei mal "x" geht nicht

Weniger WTF bei eval() und arguments:

Im Strict Mode sind eval und arguments (enthält in Funktionen alle Argumente dieser Funktion) reservierte Namen, die nicht überschrieben werden können. Das auf die aufrufende Funktion verweisende arguments.callee ist aufgrund seiner Arbeitsweise ein großes Hindernis für die Performanceoptimierung-Mechanismen in den Browsern und wird unter anderem deshalb abgeschafft. Außerdem sind die Argumente einer Funktion nicht mehr fest an arguments gebunden – arguments enthält im Strict Mode immer die Original-Werte, mit denen die Funktion ursprünglich aufgerufen wurde, Modifikationen werden nicht mehr übertragen:

function foo(x){
    x++;
    console.log(arguments[0]); // 43
}
foo(42);

function bar(x){
    "use strict";
    x++;
    console.log(arguments[0]); // 42 dank Strict Mode
}
bar(42);

Weniger WTF bei this: Bei Funktionsaufrufen wie foo(); ist in normalem JS this in der Funktion das globale Objekt. Wenn man in dieser Situation versucht, Methoden und Eigenschaften für this zu definieren (weil man sich zum Beispiel aufgrund eine Programmierfehlers fälschlicherweise im Methoden- oder Constuctorkontext wähnt), produziert man globale Variablen ‐ und zwar ohne es zu merken! Deshalb gilt im Strict Mode: this ist in Funktionsaufrufen undefined, so dass Irrtümer wie ein vergessenes new schneller auffallen – undefined kann man schließlich nicht mit neuen Eigenschaften oder Methoden versehen, ohne dass es Fehler hagelt.

Weniger Freiheiten bei Funktionsstatements: Funktionsstatements wie function foo(){} erlauben moderne Browser an so ziemlich jeder Stelle im Code, kommen aber in If-Blöcken oder Schleifen zu sehr unterschiedlichen Ergebnissen bei der Auswertung dieser Statements. Um dieses Problem in aus dem Weg zu räumen, dürfen im Strict Mode Funktionsstatements nur noch direkt in einem Script oder einer Funktion stehen, nicht innerhalb von If-Blöcken oder Schleifen:

"use strict";
if(true){
    function foo(){} // SyntaxError
}

function bar(){}     // Kein Problem

Weniger with-Statement: Niemand sollte je das with-Statement verwenden, also verbietet es der Strict Mode und erklärt es zu einem Syntaxfehler.

Weniger oktale Syntax: Alle Browser interpretieren Zahlen mit vorangestellter Null als Oktalzahl (0644 == 420) – und das, obwohl es gar nicht im ECMAScript-Standard vorgeschrieben ist. Da Oktalzahlen selten nützlich und oft verwirrend sind, sind sie im Strict Mode verboten und produzieren einen Syntaxfehler.

Mehr reservierte Wörter: implements, interface, let, package, private, protected, public, static, und yield sind im Strict Mode reservierte Namen für zukünftige ECMAScript-Versionen und können nicht mehr als Variablennamen u.Ä. verwendet werden:

"use strict";
var package = 42; // package is a reserved identifier

Fazit und Fallen

Der Strict Mode ist nicht viel mehr, als ein um einige Fallen bereinigtes JavaScript. Da er ein Subset von „normalem“ JavaScript darstellt sollten Strict-Mode-Scripts problemlos in jedem modernen und unmodernen Browser funktionieren. Neu ist eigentlich nur, dass man im Strict Mode so programmiert, als würde einem ständig Douglas Crockford über die Schulter schauen.

Die einzig große Falle könnte dann zuschnappen, wenn performancebedingt mehrere JS-Dateien zusammenfügt werden; ist nur ein einziges Strict-Mode-Script dabei, wird der gesamte Code nach den strengen Regeln ausgewertet, was, wenn nicht alle Scripts hierfür vorbereitet sind, übel enden könnte. Als Vorsichtsmaßnahme kann man, wenn man es nicht ohnehin schon macht, seine Scripts in eine sofort ausgeführten Funktion kapseln. So kann man sich sicher sein, dass der Strict Mode immer auf das eigene Script beschränkt bleibt:

(function(){
    "use strict";
    // Code
})()

Sollte man schon heute den Strict Mode verwenden? Schwierige Frage. Einerseits müsste, wie bereits erwähnt, jeder Browser Strict-Mode-Code ausführen – nur wird eben nicht jeder Browser die diversen Neuheiten durchsetzen. Da es aber zu Zeit mit dem Firefox 4 nur einen einzigen Browser gibt, der den Strict Mode (vollständig) implementiert, hat man als Webentwickler nur diesen einen Browser als Testplattform zur Verfügung. Und nun stelle man sich vor, es gäbe einen Bug im Strict Mode des Firefox 4, der Code, der eigentlich Fehler auslösen müsste, passieren lässt – und dann updaten eines Tages alle anderen Browserhersteller ihre Produkte mit einem korrekten Strict Mode und das nur im Firefox getestete Script funktioniert nicht mehr …

Für den Moment ist es vielleicht nicht die schlechteste Idee, Scripts im Strict Mode zu entwickeln, das "use strict"; aber zu entfernen bevor man den Code in die freie Wildbahn loslässt. So nutzt man beim Programmieren alle Vorteile, hat aber am Ende mit absoluter Sicherheit ein funktionierendes Programm – und das ist ja auch nicht ganz unwichtig.