»"use strict";« in JavaScript
Die Auswertungsanweisung »"use strict";« (oder »'use strict';«) hat den Effekt, daß sie die JavaScript -Implementation auf den strengen Modus umstellt, in dem einige fragwürdige Kommandos als Fehler abgelehnt und einige andere Kommandos eine andere Bedeutung haben werden. Die Verwendung von »"use strict";« wird empfohlen, weil sie dabei hilft, Programmierfehler zu finden.
- Die use-strict-Anweisung
.------------. .-.
--->.--->( "use strict" )---.--->( ; )--->
| '------------' ^ '-'
| .------------. |
'--->( 'use strict' )---'
'------------'
Vorteile von »"use strict";«
- Einige Fehler werden deutlich gemeldet und nicht versteckt. Dies erleichtert das Finden von Fehlern.
- In einigen Fällen können Programmteile mit dem strengen Modus schneller ausgeführt werden.
- Einige Schreibweisen, die voraussichtlich in zukünftigen Versionen von ECMAScript als Fehler gelten werden, werden schon jetzt als Fehler gemeldet. Dadurch ist es leichter, zukunftssicheren Code zu schreiben.
Kein versehentliches Anlegen neuer Eigenschaften
- Protokoll nach Neustart des Browsers
examplename = 5
5
- Protokoll nach Neustart des Browsers
"use strict"; examplename = 5
ReferenceError: assignment to undeclared variable a
Eigenschaften des globalen Objekts können weiterhin mit dem expliziten »this.« angelegt werden, beispielsweise »this.examplename=5«.
Kein stilles Scheitern einer Zusweisung
- Protokoll nach Neustart des Browsers
NaN = 5 /* stilles Scheitern */
5
- Protokoll nach Neustart des Browsers
"use strict"; NaN = 5 /* lautes Scheitern */
TypeError: "NaN" is read-only
Kein stilles Scheitern beim Löschen
- Protokoll nach Neustart des Browsers
delete this.undefined /* stilles Scheitern */
false
- Protokoll nach Neustart des Browsers
"use strict"; delete this.undefined /* lautes Scheitern */
TypeError: property "undefined" is non-configurable and can't be deleted
Im strengen Modus ist nur das Löschen von Eigenschaften erlaubt; diese müssen dazu mit einem echten Eintragsausdruck (mit einem Punkt) angegeben werden.
- Protokoll nach Neustart des Browsers
a = 5
5
"use strict"; delete a;
SyntaxError: applying the 'delete' operator to an unqualified name is deprecated
"use strict"; delete this.a;
true
Schutz einiger Namen als Quasi-Schlüsselwörter
Zuweisungen an »eval« und »arguments« sind im strengen Modus nicht erlaubt. Diese werden dadurch denn Schlüsselwörtern ähnlicher als den Bezeichnern.
- Protokoll nach Neustart des Browsers
eval = 2
2
"use strict"; eval = 2
- im strengen Modus nicht erlaubte Namen (wie eventuelle zukünftige Schlüsselwörter oder einige Java -Schlüsselwörter)
- implements interface package private protected public
- sonstige Wörter, die im strengen Modus nicht als Namen verwendet werden dürfen
- eval arguments
Führende Nullen
Führende Nullen bei ganzzahligen Literalen sind im strengen Modus verboten, da die versehentliche Verwendung einer führenden Null zu einem anderen als den beabsichtigten Wert führen könnte.
- Auswertung
()=>{ 05; }
function ()
- Auswertung
()=>{ "use strict"; 05; }
SyntaxError: "0"-prefixed octal literals and octal escape sequences are deprecated; for octal literals use the "0o" prefix instead
»"use strict";« gilt für den ihm folgenden Teil einer Quelltexteinheit.
- Protokoll
02; "use strict"; 3
3
»"use strict";« gilt nicht für Teile anderer Quelltexteinheiten, selbst wenn diese nach »"use strict";« in einer Quelltexteinheit aufgerufen werden.
- Protokoll
f = ()=> 05
function f()
"use strict"; f()
5
"use strict"; 05
SyntaxError
»"use strict";« gilt nicht für das Laufzeitverhalten, sondern nur für den Quelltext. Daher können Numeralia in Zeichenfolgen weiterhin umgewandelt werden, auch wenn sie mit einer Null beginnen.
- Protokoll
"use strict"; +"010"
10
Das globale »"use strict";«
Ein Skript wird in Quelltexteinheiten (“[syntactic ]source text unit ”) unterteilt, die wir auch kurz Einheiten nennen. Was eine Quelltexteinheit genau ist, hängt von der verwendeten JavaScript -Implementation ab.
Damit »"use strict";« für eine Einheit beachtet wird, muß es ganz am Anfang jener Einheit stehen. Es stellt dann den strengen Modus für die gesamte Einheit ein. Solch ein »"use strict";« nennen wir auch ein globales »"use strict";«.
- Skript
"use strict";
/* ... */
Das lokale »"use strict";«
»"use strict";« kann auch als erste Anweisung im Block einer Blockfunktion verwendet werden, um für jenen Block den strengen Modus zu festzulegen.
- Auswertung
()=>{ "use strict"; /* ... */ }
function ()
Das »"use strict";« in »eval«
»"use strict";« kann auch als erste Anweisung in der Sequenz in einem eval-Aufruf verwendet werden, um für jene Sequenz den strengen Modus zu festzulegen. Wenn der strenge Modus bereits für die Umgebung des eval-Aufrufs eingestellt wurde, wird er nicht immer automatisch für jene Sequenz übernommen.
- Auswertung
eval( "'use strict'; /* ... */" );
function ()
Stilregeln
ℛ Stilregel Da der strenge Modus dabei hilft, Fehler zu entdecken, ist die Verwendung von »"use strict;"« empfehlenswert.
Diese Stilregel gilt aber nur für den Fall, daß »"use strict;"« in neu geschriebenem Code von einem Programmierer verwendet wird, der sich der Konsequenzen bewußt ist.
Auf keinen Fall darf »"use strict;"« einfach zu bestehendem Code hinzugefügt werden, da es diesen dann nicht verbessert, sondern seine Bedeutung so verändern könnte, daß ohne »"use strict;"« vollkommen korrekter Code nicht mehr korrekt arbeitet!
Die Übernahme von »"use strict";« durch »eval« ⃗
Ein direkter Aufruf von »eval« ist ein Aufruf von »eval«, in dem die Funktion ohne Kontext aufgerufen und mit dem Namen »eval« bezeichnet wird. Wenn ein Ausdruck angegeben wird, der die Funktion als Ergebnis liefert, aber nicht »eval« lautet, ist es kein direkter Aufruf, außer »eval« wurde einfach nur eingeklammert.
Bei einem direkten Aufruf von »eval«, wird der strenge Modus von der Umgebung des Aufrufs übernommen, falls er für diese gilt.
- Direkter Aufruf
"use strict"; eval( "03" );
SyntaxError: "0"-prefixed octal literals and octal escape sequences are deprecated; for octal literals use the "0o" prefix instead
- Kein direkter Aufruf
"use strict"; this.eval( "03" );
3
»"use strict";« als Auswertungsanweisung ⃗
Bei »"use strict";« handelt es sich zunächst einmal um eine Auswertungsanweisung, die eine Zeichenfolge auswertet. Die Auswertung einer Zeichenfolge sollte keine Wirkung haben. Es gibt aber eine Sonderregel für die Anweisung »"use strict";«, derzufolge das Vorkommen jener Anweisung an bestimmten Stellen die JavaScript -Implementation dazu bewegt, folgende Kommandos im strengen Modus zu interpretieren.
Quellen *
- Quellen *
http://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
Der direkte Aufruf von »eval« *
Hier wird hergeleitet, warum die beiden folgenden Aufruf von »eval«, in ECMAScript 2016 direkte Aufrufe sind.
- Zwei Aufrufe von »eval«
"use strict"; eval( "03" );
"use strict"; const eval = window.eval; eval( "03" );
0) Beim Aufruf »eval( "05" )« wird der Bezeichner »eval« zuerst nach folgender Regel interpretiert.
- 12.1.6 Runtime Semantics: Evaluation of IdentifierReference : Identifier
- Return ? ResolveBinding(StringValue of Identifier)
Also hier »ResolveBinding( "eval" )«.
1) Danach folgt hier (vereinfacht):
- 8.3.2 ResolveBinding ( name [ , env ] )
- Return ? GetIdentifierReference( global lexical environment, "eval" )
2) Danach folgt hier (vereinfacht):
- 8.1.2.1 GetIdentifierReference( global lexical environment, name )
- Return [ null, "eval" ]
»eval« ist ein Eintrag im globalen Objekt, aber nicht in der globalen lexikalischen Umgebung. Daher wird es in dieser nicht gefunden, und der base-Wert der sich ergebenden Referenz ist »null«. (Hier wird verwendet: 8.1 „The global environment's outer environment reference is null.“, dies wird für die Schritte 4 und 5 in 8.1.2.1 mit einer Rekursion verwendet.)
3) Nun müssen wird (laut 12.3.4.1) folgendes auswerten:
- 6.2.3 IsPropertyReference( [null, eval] )
- true if either the base value is an object or HasPrimitiveBase(V) is true
Da hier der base-Wert gleich »null« ist, ist dies »false«. (Es wäre auch »false«, wenn man »eval« noch in die globale lexikalische Umgebung einbauen würde, da diese kein Objekt ist.)
4) Nun können wir den Funktionsaufruf betrachten.
- 12.3.4.1 Runtime Semantics: Evaluation of a function call
- 3. If Type(ref) is Reference and IsPropertyReference(ref) is false and GetReferencedName(ref) is "eval", then
- a. If SameValue(func, %eval%) is true, then
Diese Bedingungen bestimmen einen direkten eval-Aufruf und sind nun tatsächlich alle erfüllt.