Dieser Artikel ist Teil einer Serie:
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()
undarguments
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.
Kommentare (14)
Holger ¶
12. April 2011, 09:20 Uhr
Vielen Dank für die ausführliche und verständliche Zusammenfassung der Neuerungen in ES5.
molily ¶
12. April 2011, 10:32 Uhr
Chromium- und WebKit-Nightlies implementieren den Strict Mode auch schon weitesgehend, sodass man zumindest einen Vergleich auf Basis von Beta-Versionen hat, wenn Firefox 4 sich seltsam verhält.
Nico ¶
12. April 2011, 11:09 Uhr
Hat der strict-Modus nun Einfluss auf die Ausführung eines Codes? Anders gefragt: Würde ein gleiches Stück Code, das im strict-Modus keine Fehler wirft, im strict-Modus und im normalen Modus zum gleichen Ergebnis führen? Wenn ich deinen letzten Absatz richtig verstanden habe, ist dem ja so, oder nicht?
Ole ¶
12. April 2011, 12:07 Uhr
Hey,
Danke fuer diesen wirklich sehr guten Artikel Peter!
Eine frage bleibt bei mir allerdings noch offen, wie verhaelt es sich bei inline JavaScript, reicht einmal pro Seite oder doch pro script tag?
LG
Peter ¶
12. April 2011, 17:30 Uhr
Einmal reicht.
Peter ¶
12. April 2011, 17:32 Uhr
Zitat Nico:
Das Ergebnis wird das gleiche sein, aber die Ausführung kann sich in sofern ändern, als dass die Browser durch den Wegfall von
with
undarguments.callee
die Performance besser optimieren können.Chris ¶
12. April 2011, 18:33 Uhr
Schöner Beitrag, sehr aufschlussreich.
Wann kommt endlich dein erstes Buch zu JavaScript-Grundlagen? Dann würde ich mir die Sprache ja doch mal ausführlich antun … ;-)
Peter ¶
13. April 2011, 07:26 Uhr
Kauf dir lieber das hier.
Die Preview 1 des IE10 hat im übrigen auch Strict Mode.
Sacha ¶
13. April 2011, 15:10 Uhr
Douglas Crockford schaut uns doch via JSLint eh schon dauern über die Schulter! ;)
realityking ¶
14. Juli 2011, 18:35 Uhr
Das stimmt so nicht ganz, ein script was, im strict mode geschrieben, sich darauf verlässt, dass sich arguments nicht verändert wird nicht mehr korrekt funktionieren wenn es ohne strict mode ausgeführt wird. Man sollte also sehr vorsichtig sein heute schon scripte im strict mode zu schreiben.
Peter ¶
14. Juli 2011, 19:07 Uhr
Beispiel?
realityking ¶
14. Juli 2011, 19:12 Uhr
Hast du schon selbst im Abschnitt "Weniger WTF bei eval() und arguments" geliefert.
Peter ¶
14. Juli 2011, 19:19 Uhr
Ah so, jetzt verstehe ich deinen Kommentar. Was ich nicht verstehe ist, worauf du hinaus möchtest. Strict-JS ist logischerweise ein Subset von Normal-JS und nicht umgekehrt, dass manche alte Technik in der neuen Welt nicht mehr funktioniert, ist doch eigentlich nur folgerichtig.
realityking ¶
14. Juli 2011, 19:34 Uhr
Das Problem entsteht wenn ich mein script mit "use strict"; in einem Browser der das unterstützt entwickle und dabei arguments so benutze das ich mich darauf verlasse das sich der Wert nicht verändert, im schlimmsten Fall nur in einem Randbereich.
Wenn ich mich jetzt auf den - oft vertretenen - Standpunkt stelle, dass non strict JS ist ein superset von strict JS ist. Da her dass es mich nur vor schlechtem code schützt aber wenn alles mit strict funktioniert, funktioniert es immer noch ohne strict.
Das ist aber hier genau nicht der Fall, wenn ich so programmiere funktioniert mein script in non strict browsern aber nicht mehr (richtig). Deswegen würde ich den strict mode (derzeit) nur intern zum testen benutzen und sehr sehr vorsichtig sein den strict mode auf einer öffentlichen webseite zu benutzen.
Ein wenig googlen fördert zutage, dass die Mozilla Dokumentation mir zustimmt.