Warum ist JavaScript im strikten Modus erforderlich?

Der strikte Modus ist ein wichtiger Bestandteil des modernen JavaScript. In diesem Modus können Entwickler eine eingeschränktere Syntax als die Standardsyntax verwenden.

Die Semantik des strikten Modus unterscheidet sich vom traditionellen nicht-strikten Modus, der manchmal als "schlampiger Modus" bezeichnet wird. In diesem Modus sind die Syntaxregeln der Sprache nicht so streng, und wenn einige Fehler auftreten, benachrichtigt das System den Benutzer nicht darüber. Das heißt, Fehler können ignoriert und der Code, in dem sie gemacht werden, kann weiter ausgeführt werden. Dies kann zu unerwarteten Ergebnissen bei der Codeausführung führen.



Im strengen Modus werden einige Änderungen an der Semantik von JavaScript vorgenommen. Es verhindert, dass das System die Augen vor Fehlern verschließt, indem es entsprechende Ausnahmen auslöst. Dadurch wird die Programmausführung gestoppt.

Darüber hinaus hilft der Strict-Modus beim Schreiben von Programmen, bei denen es keine Mängel gibt, die JS-Engines daran hindern, den Code zu optimieren. Außerdem ist es in diesem Modus verboten, Syntaxelemente zu verwenden, die in zukünftigen Versionen der Sprache möglicherweise eine besondere Bedeutung haben.

Funktionen zur Verwendung des Strict-Modus


Der Strict-Modus kann auf einzelne Funktionen oder auf ein gesamtes Skript angewendet werden. Es kann nicht nur auf einzelne Anweisungen oder in geschweiften Klammern gesetzte Codeblöcke angewendet werden. Um den strikten Modus auf der Ebene des gesamten Skripts zu verwenden, müssen Sie am Anfang der Datei vor allen anderen Befehlen den Befehl "use strict" oder 'use strict' construct setzen.

Wenn das Projekt über einige Skripte verfügt, die den strikten Modus nicht verwenden, und über andere, die diesen Modus verwenden, kann es vorkommen, dass diese Skripte zusammengeführt werden.

Dies führt dazu, dass sich Code, der nicht im strikten Modus ausgeführt werden soll, in einem solchen Zustand befindet, wenn das System versucht, ihn im strikten Modus auszuführen. Das Gegenteil ist auch möglich - Code, der für den strengen Modus geschrieben wurde, fällt in den nicht-strengen Modus. Daher ist es am besten, „strenge“ und „nicht strenge“ Skripte nicht zu mischen.

Wie bereits erwähnt, kann der strikte Modus auf einzelne Funktionen angewendet werden. Zu diesem Zweck muss die Konstruktion "use strict" oder 'use strict' vor allen anderen Befehlen am Anfang des Funktionskörpers platziert werden. Der strikte Modus bei diesem Ansatz gilt für alles, was sich im Hauptteil der Funktion befindet, einschließlich verschachtelter Funktionen.

Zum Beispiel:

 const strictFunction = ()=>{  'use strict';  const nestedFunction = ()=>{    //        } } 

In JavaScript-Modulen, die im ES2015-Standard enthalten waren, ist der strikte Modus standardmäßig aktiviert. Wenn Sie mit ihnen arbeiten, müssen Sie sie daher nicht explizit einschließen.

Änderungen, die im strikten Modus am JS-Code vorgenommen wurden


Der strenge Modus wirkt sich sowohl auf die Syntax des Codes als auch auf das Verhalten des Codes während der Programmausführung aus. Fehler im Code werden in Ausnahmen umgewandelt. Die Tatsache, dass im stillen Modus still im strengen Modus abstürzt, verursacht eine Fehlermeldung. Dies ähnelt dem Verhalten des Systems bei Syntaxfehlern im Lax-Modus. Im strikten Modus wird die Arbeit mit Variablen vereinfacht, die Verwendung der eval Funktion und des arguments Objekts streng geregelt und die Arbeit mit Konstrukten, die in zukünftigen Versionen der Sprache implementiert werden können, optimiert.

▍ Konvertieren Sie stille Fehler in Ausnahmen


Stille Fehler werden im strengen Modus in Ausnahmen umgewandelt. Im laxen Modus reagiert das System nicht explizit auf solche Fehler. Im strikten Modus führt das Vorhandensein solcher Fehler zur Inoperabilität des Codes.

Aus diesem Grund ist es schwierig, den Fehler zu machen, eine globale Variable versehentlich zu deklarieren, da Variablen und Konstanten im strikten Modus nicht ohne die Anweisungen var , let oder const deklariert werden können. Infolgedessen führt das Erstellen von Variablen ohne diese Anweisungen zur Funktionsunfähigkeit des Programms. Wenn Sie beispielsweise versuchen, den folgenden Code auszuführen, wird eine ReferenceError Ausnahme ReferenceError :

 'use strict'; badVariable = 1; 

Solcher Code kann nicht im strikten Modus ausgeführt werden, da bei badVariable strikten Modus die globale Variable badVariable . Der strikte Modus schützt den Programmierer vor dem versehentlichen Erstellen globaler Variablen.

Der Versuch, Code auszuführen, der im normalen Modus einfach nicht funktioniert, löst jetzt eine Ausnahme aus. Als Fehler gelten alle falschen syntaktischen Konstruktionen, die im lax-Modus einfach ignoriert wurden.

So können Sie beispielsweise im strikten Modus keine Wertzuweisungsoperationen für schreibgeschützte Entitäten wie arguments , NaN oder eval ausführen.

Im strikten Modus wird beispielsweise in folgenden Fällen eine Ausnahme ausgelöst:

  • ein Versuch, einer schreibgeschützten Eigenschaft einen Wert zuzuweisen, beispielsweise einer Art wiederbeschreibbarer globaler Eigenschaft;
  • ein Versuch, einen Wert in eine Eigenschaft zu schreiben, die nur einen Getter enthält;
  • Ein Versuch, etwas in eine Eigenschaft eines nicht erweiterbaren Objekts zu schreiben.

Hier sind Beispiele für Syntaxkonstrukte, die zu strengen Modusausnahmen führen:

 'use strict'; let undefined = 5; let Infinity = 5; let obj = {}; Object.defineProperty(obj, 'foo', { value: 1, writable: false }); obj.foo = 1 let obj2 = { get foo() { return 17; } }; obj2.foo = 2 let fixedObj = {}; Object.preventExtensions(fixedObj); fixed.bar= 1; 

Der Versuch, solche Codefragmente im strengen Modus auszuführen, TypeError eine TypeError Ausnahme aus. Beispielsweise sind undefined und Infinity globale Entitäten, deren Werte nicht überschrieben werden können, und die Eigenschaft foo des Objekts obj unterstützt kein erneutes obj . Die foo Eigenschaft von obj2 hat nur einen Getter. Das fixedObj Objekt fixedObj mit der Object.preventExtensions Methode nicht erweiterbar Object.preventExtensions .

Ein Versuch, eine nicht TypeError zu löschen, führt ebenfalls zu TypeError :

 'use strict'; delete Array.prototype 

Im strengen Modus ist es nicht möglich, einem Objekt Eigenschaften mit demselben Namen zuzuweisen. Daher führt der Versuch, den folgenden Code auszuführen, zu einem Syntaxfehler:

 'use strict'; let o = { a: 1, a: 2 }; 

Im strengen Modus müssen Funktionsparameternamen eindeutig sein. Wenn beispielsweise im nicht strengen Modus zwei Funktionsparameter den gleichen Namen haben, ist der Parameterwert beim Übergeben der Argumentfunktion der Wert, der in das zuletzt deklarierte Argument fällt.

Im Strict-Modus sind Parameter von Funktionen mit demselben Namen nicht zulässig. Daher führt der Versuch, den folgenden Code auszuführen, zu einem Syntaxfehler:

 'use strict'; const multiply = (x, x, y) => x*x*y; 

Im strengen Modus können Sie die Oktalnotation von Zahlen vor der Zahl mit Null nicht verwenden. Dies ist nicht in der Spezifikation enthalten, diese Funktion wird jedoch von Browsern unterstützt.

Dieser Zustand verwirrt die Entwickler und zwingt sie zu der Annahme, dass die 0 vor der Zahl ohne großen Sinn einfach ignoriert wird. Wenn Sie im strengen Modus versuchen, eine Zahl zu verwenden, deren Anfang 0 ist, wird ein Syntaxfehler verursacht.

Der strikte Modus verbietet auch die Verwendung von Konstrukten, die die Optimierung behindern. Bevor der Interpreter eine Codeoptimierung durchführt, muss er wissen, dass die Variable genau dort gespeichert ist, wo sie laut Interpreter gespeichert ist. Im strengen Modus sind Dinge, die die Optimierung beeinträchtigen, verboten.

Ein Beispiel für ein solches Verbot ist die with Anweisung. Wenn Sie diese Anweisung verwenden, verhindert dies, dass der JS-Interpreter herausfindet, auf welche Variable oder welche Eigenschaft wir verweisen, da möglicherweise eine Entität mit demselben Namen sowohl außerhalb als auch innerhalb des Blocks der with Anweisung vorhanden ist.

Angenommen, es gibt einen Code wie diesen:

 let x = 1; with (obj) {  x; } 

Der Interpreter kann nicht feststellen, ob die Variable x im with Block auf die externe Variable x oder auf die obj.x Eigenschaft des obj Objekts obj .

Infolgedessen ist nicht klar, wo genau sich der x Wert im Speicher befindet. Um solche Unklarheiten zu beseitigen, ist die Verwendung der with Anweisung im strikten Modus verboten. Mal sehen, was passiert, wenn Sie versuchen, den folgenden Code im strikten Modus auszuführen:

 'use strict'; let x = 1; with (obj) {  x; } 

Das Ergebnis dieses Versuchs ist ein Syntaxfehler.

Auch im strikten Modus ist es verboten, Variablen im Code zu deklarieren, der an die eval Methode übergeben wird.

Im normalen Modus führt beispielsweise ein Befehl der Form eval('let x') zur Deklaration der Variablen x . Dadurch können Programmierer Variablendeklarationen in Zeichenfolgen ausblenden, was dazu führen kann, dass die Definitionen derselben Variablen außerhalb von eval überschrieben werden.

Um dies zu verhindern, ist es im strikten Modus verboten, Variablen im Code zu deklarieren, die als Zeichenfolge an die eval Methode übergeben werden.

Der strikte Modus verbietet auch das Löschen regulärer Variablen. Daher führt der Versuch, den folgenden Code auszuführen, zu einem Syntaxfehler:

 'use strict'; let x; delete x; 

▍ Verbot falscher Syntaxkonstrukte


Im strengen Modus ist die falsche Verwendung von eval und arguments verboten. Dies ist ein Verbot aller Arten von Manipulationen mit ihnen. Dies ist beispielsweise so etwas wie das Zuweisen neuer Werte, wobei deren Namen als Variablennamen, Funktionen und Funktionsparameter verwendet werden.

Hier sind Beispiele für den Missbrauch von eval und arguments :

 'use strict'; eval = 1; arguments++; arguments--; ++eval; eval--; let obj = { set p(arguments) { } }; let eval; try { } catch (arguments) { } try { } catch (eval) { } function x(eval) { } function arguments() { } let y = function eval() { }; let eval = ()=>{ }; let f = new Function('arguments', "'use strict'; return 1;"); 

Im strikten Modus können Sie keine Aliase für das arguments Objekt erstellen und über diese Aliase neue arguments festlegen.

Wenn im normalen Modus der erste Parameter der Funktion a ist, führt das Festlegen des Werts von a im Funktionscode auch zu einer Änderung des Werts in arguments[0] . Im strikten Modus enthalten arguments immer die Liste der Argumente, mit denen die Funktion aufgerufen wurde.

Angenommen, Sie haben den folgenden Code:

 const fn = function(a) {  'use strict';  a = 2;  return [a, arguments[0]]; } console.log(fn(1)) 

Die Konsole wird [2,1] . Dies liegt daran, dass beim Schreiben eines Werts von 2 in a kein Wert von 2 in arguments[0] .

▍Performance optimieren


Im strengen Modus wird die Eigenschaft arguments.callee nicht unterstützt. Im normalen Modus wird der Name der übergeordneten Funktion der Funktion zurückgegeben, deren Eigenschaft callee des arguments untersucht wird.

Die Unterstützung dieser Eigenschaft beeinträchtigt Optimierungen, z. B. Inlining-Funktionen, da für die Verwendung von arguments.callee die Verfügbarkeit eines Verweises auf eine nicht eingebettete Funktion erforderlich ist, wenn auf diese Eigenschaft zugegriffen wird. Im strengen Modus löst die Verwendung von arguments.callee eine TypeError Ausnahme aus.

Im strikten Modus muss das this nicht immer ein Objekt sein. Wenn this Funktion unter normalen Bedingungen mit call , apply oder bind an etwas gebunden ist, das kein Objekt ist, an einen Wert eines primitiven Typs wie undefined , null , number oder boolean , sollte ein solcher Wert ein Objekt sein.

Wenn sich der Kontext in etwas ändert, das kein Objekt ist, tritt an seine Stelle ein globales Objekt. Zum Beispiel window . Dies bedeutet, dass, wenn Sie eine Funktion aufrufen, indem Sie this auf einen Wert setzen, der kein Objekt ist, statt auf diesen Wert, ein Verweis auf das globale Objekt in this Wert fällt.

Betrachten Sie ein Beispiel:

 'use strict'; function fn() {  return this; } console.log(fn() === undefined); console.log(fn.call(2) === 2); console.log(fn.apply(null) === null); console.log(fn.call(undefined) === undefined); console.log(fn.bind(true)() === true); 

Alle console.log Befehle geben " true , da der Wert this console.log in der Funktion im strikten Modus nicht automatisch durch einen Verweis auf das globale Objekt ersetzt wird, wenn this auf einen Wert festgelegt ist, der kein Objekt ist.

▍ Sicherheitsrelevante Änderungen


Im strengen Modus können Sie die Funktionseigenschaften caller und arguments öffentlich machen. Fakt ist, dass der caller beispielsweise Zugriff auf die Funktion gewähren kann, die die Funktion aufgerufen hat, auf deren caller wir zugreifen.

Das arguments Objekt speichert die Argumente, die beim Aufruf an die Funktion übergeben wurden. Wenn wir zum Beispiel eine Funktion fn , bedeutet dies, dass Sie über fn.caller auf die Funktion zugreifen können, die die Funktion aufgerufen hat, und mit fn.arguments können Sie die Argumente fn.arguments , die beim fn.arguments an fn .

Diese Funktionen stellen ein potenzielles Sicherheitsrisiko dar. Infolgedessen ist der Zugriff auf diese Eigenschaften im strengen Modus verboten.

 function secretFunction() {  'use strict';  secretFunction.caller;  secretFunction.arguments; } function restrictedRunner() {  return secretFunction(); } restrictedRunner(); 

Im vorherigen Beispiel können wir im strikten Modus nicht auf die secretFunction.caller und secretFunction.arguments . Tatsache ist, dass diese Eigenschaften verwendet werden können, um einen Stapel von Funktionsaufrufen abzurufen. Wenn Sie versuchen, diesen Code auszuführen, wird eine TypeError Ausnahme TypeError .

Im strengen Modus können Bezeichner, die möglicherweise in zukünftigen Versionen von JavaScript verwendet werden, nicht zum Benennen von Variablen oder Eigenschaften von Objekten verwendet werden. Zum Beispiel sprechen wir über die folgenden Bezeichner: implements , interface , let , package , private , protected , public , static und yield .

In ES2015 und späteren Versionen des Standards wurden diese Bezeichner zu reservierten Wörtern. Und sie können nicht verwendet werden, um Variablen oder Eigenschaften im strengen Modus zu benennen.

Zusammenfassung


Strenger Modus ist ein Standard, der seit vielen Jahren existiert. Es genießt eine extrem breite Browserunterstützung. Probleme mit Strict-Mode-Code können nur in älteren Browsern wie dem Internet Explorer auftreten.

Moderne Browser sollten keine Schwierigkeiten mit dem strengen JavaScript-Modus haben. Wir können daher sagen, dass dieser Modus verwendet werden sollte, um "stille" Fehler zu vermeiden und die Anwendungssicherheit zu erhöhen. Stille Fehler werden in Ausnahmen umgewandelt, die die Ausführung von Programmen behindern. Um die Sicherheit zu verbessern, können beispielsweise Strict-Mode-Mechanismen festgestellt werden, die die eval einschränken und den Zugriff auf den Funktionsaufrufstapel verhindern. Darüber hinaus erleichtert die Verwendung des strikten Modus die Codeoptimierung für die JS-Engine und zwingt den Programmierer zum sorgfältigen Umgang mit reservierten Wörtern, die möglicherweise in zukünftigen Versionen von JavaScript Verwendung finden.

Sehr geehrte Leser! Verwenden Sie den strikten Modus, wenn Sie JS-Code für Ihre Projekte schreiben?


Source: https://habr.com/ru/post/de477284/


All Articles