Kapitel 23. Standardisierte globale Variablen
Inhaltsverzeichnis
Das Buch kaufen
(Werbung, bitte nicht blockieren.)

Kapitel 23. Standardisierte globale Variablen

Dieses Kapitel ist eine Referenz für die globalen Variablen, die durch die ECMAScript-Spezifikation standardisiert wurden. Webbrowser verfügen über weitere globale Variablen, die auf MDN aufgeführt sind. Alle globalen Variablen sind (eigene oder geerbte) Eigenschaften des globalen Objekts (window in Browsern; siehe Das globale Objekt).

Error-Konstruktoren

Details zu diesen Konstruktoren finden Sie in Fehlerkonstruktoren

  • Error
  • EvalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

Nicht-Konstruktor-Funktionen

Mehrere globale Funktionen sind keine Konstruktoren. Sie werden in diesem Abschnitt aufgeführt.

Kodieren und Dekodieren von Text

Die folgenden Funktionen behandeln mehrere Arten der URI-Kodierung und -Dekodierung:

encodeURI(uri)

Kodiert Sonderzeichen in uri prozentual. Sonderzeichen sind alle Unicode-Zeichen mit Ausnahme der folgenden:

URI-Zeichen

; , / ? : @ & = + $ #

Nicht kodiert

a-z A-Z 0-9 - _ . ! ~ * ' ( )

Zum Beispiel

> encodeURI('http://example.com/Für Elise/')
'http://example.com/F%C3%BCr%20Elise/'
encodeURIComponent(uriComponent)

Kodiert alle Zeichen in uriComponent prozentual, außer

Nicht kodiert

a-z A-Z 0-9 - _ . ! ~ * ' ( )

Im Gegensatz zu encodeURI werden auch Zeichen kodiert, die in URLs und Dateinamen eine Rolle spielen. Sie können diese Funktion also verwenden, um beliebigen Text in einen gültigen Dateinamen oder einen URL-Pfadabschnitt umzuwandeln. Beispiel:

> encodeURIComponent('http://example.com/Für Elise/')
'http%3A%2F%2Fexample.com%2FF%C3%BCr%20Elise%2F'
decodeURI(encodedURI)

Dekodiert eine durch Prozentzeichen kodierte URI, die von encodeURI erzeugt wurde.

> decodeURI('http://example.com/F%C3%BCr%20Elise/')
'http://example.com/Für Elise/'

encodeURI kodiert keine URI-Zeichen, und decodeURI dekodiert sie nicht, auch wenn sie korrekt kodiert wurden.

> decodeURI('%2F')
'%2F'
> decodeURIComponent('%2F')
'/'
decodeURIComponent(encodedURIComponent)

Dekodiert eine durch Prozentzeichen kodierte URI-Komponente, die von encodeURIComponent erzeugt wurde. Im Gegensatz zu decodeURI werden alle durch Prozentzeichen kodierten Zeichen dekodiert.

> decodeURIComponent('http%3A%2F%2Fexample.com%2FF%C3%BCr%20Elise%2F')
'http://example.com/Für Elise/'

Die folgenden sind veraltet

  • escape(str) kodiert str prozentual. Es ist veraltet, da es Nicht-ASCII-Zeichen nicht korrekt behandelt. Verwenden Sie stattdessen encodeURIComponent().
  • unescape(str) dekodiert str prozentual. Es ist veraltet, da es Nicht-ASCII-Zeichen nicht korrekt behandelt. Verwenden Sie stattdessen decodeURIComponent().

Zahlen kategorisieren und parsen

Die folgenden Methoden helfen beim Kategorisieren und Parsen von Zahlen:

JavaScript-Code dynamisch auswerten über eval() und new Function()

Dieser Abschnitt untersucht, wie Code in JavaScript dynamisch ausgewertet werden kann.

Code auswerten mit eval()

Der Funktionsaufruf:

eval(str)

wertet den JavaScript-Code in str aus. Beispiel:

> var a = 12;
> eval('a + 5')
17

Beachten Sie, dass eval() im Statement-Kontext parst (siehe Ausdrücke versus Anweisungen)

> eval('{ foo: 123 }')  // code block
123
> eval('({ foo: 123 })')  // object literal
{ foo: 123 }

eval() im Strict Mode verwenden

Für eval() sollten Sie unbedingt den Strict Mode verwenden (siehe Strict Mode). Im Sloppy Mode kann der ausgewertete Code lokale Variablen im umgebenden Geltungsbereich erstellen.

function sloppyFunc() {
    eval('var foo = 123');  // added to the scope of sloppyFunc
    console.log(foo);  // 123
}

Das kann im Strict Mode nicht passieren.

function strictFunc() {
    'use strict';
    eval('var foo = 123');
    console.log(foo);  // ReferenceError: foo is not defined
}

Selbst im Strict Mode hat der ausgewertete Code jedoch weiterhin Lese- und Schreibzugriff auf Variablen in umgebenden Geltungsbereichen. Um einen solchen Zugriff zu verhindern, müssen Sie eval() indirekt aufrufen.

Indirektes eval() wertet im globalen Geltungsbereich aus.

Es gibt zwei Möglichkeiten, eval() aufzurufen:

  • Direkt. Über einen direkten Aufruf einer Funktion mit dem Namen „eval“.
  • Indirekt. Auf irgendeine andere Weise (über call(), als Methode von window, indem sie unter einem anderen Namen gespeichert und dort aufgerufen wird usw.).

Wie wir bereits gesehen haben, führt direkter eval()-Aufruf Code im aktuellen Geltungsbereich aus.

var x = 'global';

function directEval() {
    'use strict';
    var x = 'local';

    console.log(eval('x')); // local
}

Umgekehrt führt indirekter eval()-Aufruf ihn im globalen Geltungsbereich aus.

var x = 'global';

function indirectEval() {
    'use strict';
    var x = 'local';

    // Don’t call eval directly
    console.log(eval.call(null, 'x')); // global
    console.log(window.eval('x')); // global
    console.log((1, eval)('x')); // global (1)

    // Change the name of eval
    var xeval = eval;
    console.log(xeval('x')); // global

    // Turn eval into a method
    var obj = { eval: eval };
    console.log(obj.eval('x')); // global
}

Erläuterung von (1): Wenn Sie über den Namen auf eine Variable zugreifen, ist das erste Ergebnis eine sogenannte Referenz, eine Datenstruktur mit zwei Hauptfeldern:

  • base zeigt auf die Umgebung, die Datenstruktur, in der der Wert der Variablen gespeichert ist.
  • referencedName ist der Name der Variablen.

Während eines eval()-Funktionsaufrufs stößt der Funktionsaufrufoperator (die Klammern) auf eine Referenz auf eval und kann den Namen der aufzurufenden Funktion ermitteln. Daher löst ein solcher Funktionsaufruf einen direkten eval()-Aufruf aus. Sie können jedoch einen indirekten eval()-Aufruf erzwingen, indem Sie dem Aufrufoperator keine Referenz geben. Dies wird erreicht, indem der Wert der Referenz abgerufen wird, bevor der Operator angewendet wird. Der Kommaoperator erledigt dies für uns in Zeile (1). Dieser Operator wertet den ersten Operanden aus und gibt das Ergebnis der Auswertung des zweiten Operanden zurück. Die Auswertung erzeugt immer Werte, was bedeutet, dass Referenzen aufgelöst und Funktionsnamen verloren gehen.

Indirekt ausgewerteter Code ist immer Sloppy. Das ist eine Folge davon, dass der Code unabhängig von seiner aktuellen Umgebung ausgewertet wird.

function strictFunc() {
    'use strict';

    var code = '(function () { return this }())';
    var result = eval.call(null, code);
    console.log(result !== undefined); // true, sloppy mode
}

Code auswerten mit new Function()

Der Konstruktor Function() hat die Signatur:

new Function(param1, ..., paramN, funcBody)

Erstellt eine Funktion, deren null oder mehr Parameter die Namen param1, param2 usw. haben und deren Körper funcBody ist; das heißt, die erstellte Funktion sieht so aus:

function («param1», ..., «paramN») {
    «funcBody»
}

Verwenden wir new Function(), um eine Funktion f zu erstellen, die die Summe ihrer Parameter zurückgibt.

> var f = new Function('x', 'y', 'return x+y');
> f(3, 4)
7

Ähnlich wie indirektes eval(), erstellt new Function() Funktionen, deren Geltungsbereich global ist:[18]

var x = 'global';

function strictFunc() {
    'use strict';
    var x = 'local';

    var f = new Function('return x');
    console.log(f()); // global
}

Solche Funktionen sind standardmäßig ebenfalls Sloppy.

function strictFunc() {
    'use strict';

    var sl = new Function('return this');
    console.log(sl() !== undefined); // true, sloppy mode

    var st = new Function('"use strict"; return this');
    console.log(st() === undefined); // true, strict mode
}

Bewährte Methoden

Sie sollten eval() und new Function() vermeiden. Das dynamische Auswerten von Code ist langsam und birgt potenzielle Sicherheitsrisiken. Es verhindert auch, dass die meisten Tools (wie IDEs), die statische Analysen verwenden, den Code berücksichtigen.

Oft gibt es bessere Alternativen. Brendan Eich hat zum Beispiel kürzlich einen Antipattern getwittert, der von Programmierern verwendet wird, die auf eine Eigenschaft zugreifen möchten, deren Name in einer Variablen propName gespeichert ist.

var value = eval('obj.'+propName);

Die Idee ist sinnvoll: Der Punktoperator unterstützt nur feste, statisch bereitgestellte Eigenschaftsschlüssel. In diesem Fall ist der Eigenschaftsschlüssel nur zur Laufzeit bekannt, weshalb eval() benötigt wird, um diesen Operator zu verwenden. Glücklicherweise verfügt JavaScript auch über den Klammeroperator, der dynamische Eigenschaftsschlüssel akzeptiert. Daher ist die folgende ein bessere Version des vorherigen Codes:

var value = obj[propName];

Sie sollten eval() oder new Function() auch nicht zum Parsen von JSON-Daten verwenden. Das ist unsicher. Verlassen Sie sich entweder auf die integrierte JSON-Unterstützung von ECMAScript 5 (siehe Kapitel 22) oder verwenden Sie eine Bibliothek.

Legitime Anwendungsfälle

Es gibt einige legitime, wenn auch fortgeschrittene, Anwendungsfälle für eval() und new Function(): Konfigurationsdaten mit Funktionen (was JSON nicht erlaubt), Vorlagenbibliotheken, Interpreter, Befehlszeilen und Modulsysteme.

Schlussfolgerung

Dies war ein relativ umfassender Überblick über die dynamische Auswertung von Code in JavaScript. Wenn Sie tiefer eintauchen möchten, können Sie sich den Artikel „Global eval. What are the options?“ von kangax ansehen.

Die Console API

In den meisten JavaScript-Engines gibt es ein globales Objekt, console, mit Methoden zum Protokollieren und Debuggen. Dieses Objekt ist kein fester Bestandteil der Sprache, hat sich aber zu einem De-facto-Standard entwickelt. Da ihr Hauptzweck das Debugging ist, werden die console-Methoden am häufigsten während der Entwicklung und selten in produktivem Code verwendet.

Dieser Abschnitt bietet einen Überblick über die Console API. Er dokumentiert den Status Quo ab Chrome 32, Firebug 1.12, Firefox 25, Internet Explorer 11, Node.js 0.10.22 und Safari 7.0.

Wie standardisiert ist die Console API über Engines hinweg?

Die Implementierungen der Console API variieren stark und ändern sich ständig. Wenn Sie eine autoritative Dokumentation wünschen, haben Sie zwei Möglichkeiten. Erstens können Sie sich standardähnliche Übersichten der API ansehen:

Zweitens können Sie sich die Dokumentation verschiedener Engines ansehen

Warnung

Es gibt einen Bug in Internet Explorer 9. In diesem Browser existiert das console-Objekt nur, wenn die Entwicklertools mindestens einmal geöffnet waren. Das bedeutet, dass Sie einen ReferenceError erhalten, wenn Sie sich auf console beziehen und die Tools zuvor nicht geöffnet waren. Als Workaround können Sie prüfen, ob console existiert und bei Bedarf eine Dummy-Implementierung erstellen.

Einfaches Logging

Die Console API enthält die folgenden Logging-Methoden:

console.clear()
Löscht die Konsole.
console.debug(object1, object2?, ...)
Bevorzugen Sie console.log(), was dasselbe tut wie diese Methode.
console.error(object1, object2?, ...)
Protokolliert die Parameter in der Konsole. In Browsern kann der protokollierte Inhalt mit einem „Fehler“-Symbol und/oder einem Stacktrace oder einem Link zum Code markiert sein.
console.exception(errorObject, object1?, ...]) [Nur Firebug]
Protokolliert object1 usw. und zeigt einen interaktiven Stacktrace an.
console.info(object1?, object2?, ...)
Protokolliert die Parameter in der Konsole. In Browsern kann der protokollierte Inhalt mit einem „Info“-Symbol und/oder einem Stacktrace oder einem Link zum Code markiert sein.
console.log(object1?, object2?, ...)

Protokolliert die Parameter in der Konsole. Wenn der erste Parameter eine printf-ähnliche Formatzeichenkette ist, verwenden Sie diese, um die restlichen Parameter auszugeben. Beispiel (Node.js REPL):

> console.log('%s', { foo: 'bar' })
[object Object]
> console.log('%j', { foo: 'bar' })
{"foo":"bar"}

Die einzige verlässliche plattformübergreifende Formatierungsdirektive ist %s. Node.js unterstützt %j zur Formatierung von Daten als JSON; Browser unterstützen tendenziell Direktiven, die etwas Interaktives in der Konsole protokollieren.

console.trace()
Protokolliert einen Stacktrace (der in vielen Browsern interaktiv ist).
console.warn(object1?, object2?, ...)
Protokolliert die Parameter in der Konsole. In Browsern kann der protokollierte Inhalt mit einem „Warnungs“-Symbol und/oder einem Stacktrace oder einem Link zum Code markiert sein.

Die Unterstützung auf verschiedenen Plattformen ist in der folgenden Tabelle angegeben:

ChromeFirebugFirefoxIENode.jsSafari

clear

debug

error

exception

info

log

trace

warn

exception wurde kursiv gesetzt, da es nur auf einer einzigen Plattform unterstützt wird.

Prüfen und Zählen

Die Console API enthält die folgenden Prüf- und Zählmethoden:

console.assert(expr, obj?)
Wenn expr false ist, wird obj in der Konsole protokolliert und eine Ausnahme ausgelöst. Wenn es true ist, passiert nichts.
console.count(label?)
Zählt, wie oft die Zeile mit dieser Anweisung mit diesem Label ausgeführt wurde.

Die Unterstützung auf verschiedenen Plattformen ist in der folgenden Tabelle angegeben:

ChromeFirebugFirefoxIENode.jsSafari

assert

count

Formatiertes Logging

Die Console API enthält die folgenden Methoden für formatiertes Logging:

console.dir(object)
Gibt eine Darstellung des Objekts in der Konsole aus. In Browsern kann diese Darstellung interaktiv erkundet werden.
console.dirxml(object)
Gibt den XML-Quellbaum eines HTML- oder XML-Elements aus.
console.group(object1?, object2?, ...)
Protokolliert die Objekte in der Konsole und öffnet einen verschachtelten Block, der alle zukünftigen protokollierten Inhalte enthält. Schließen Sie den Block, indem Sie console.groupEnd() aufrufen. Der Block ist zunächst erweitert, kann aber auch reduziert werden.
console.groupCollapsed(object1?, object2?, ...)
Funktioniert wie console.group(), aber der Block ist anfangs reduziert.
console.groupEnd()
Schließt eine Gruppe, die von console.group() oder console.group Collapsed() geöffnet wurde.
console.table(data, columns?)

Gibt ein Array als Tabelle aus, ein Element pro Zeile. Der optionale Parameter columns gibt an, welche Eigenschaften/Array-Indizes in den Spalten angezeigt werden. Wenn dieser Parameter fehlt, werden alle Eigenschaftsschlüssel als Tabellenspalten verwendet. Fehlende Eigenschaften und Array-Elemente erscheinen als undefined in den Spalten.

var persons = [
    { firstName: 'Jane', lastName: 'Bond' },
    { firstName: 'Lars', lastName: 'Croft', age: 72 }
];
// Equivalent:
console.table(persons);
console.table(persons, ['firstName', 'lastName', 'age']);

Die resultierende Tabelle sieht wie folgt aus:

(index)firstNamelastNameage

0

„Jane“

„Bond“

undefined

1

„Lars“

„Croft“

72

Die Unterstützung auf verschiedenen Plattformen ist in der folgenden Tabelle angegeben:

ChromeFirebugFirefoxIENode.jsSafari

dir

dirxml

group

groupCollapsed

groupEnd

table

Profiling und Zeitmessung

Die Console API enthält die folgenden Methoden für Profiling und Zeitmessung:

console.markTimeline(label) [Nur Safari]
Dasselbe wie console.timeStamp.
console.profile(title?)
Schaltet das Profiling ein. Der optionale title wird für den Profilbericht verwendet.
console.profileEnd()
Beendet das Profiling und gibt den Profilbericht aus.
console.time(label)
Startet einen Timer mit dem Label label.
console.timeEnd(label)
Stoppt den Timer mit dem Label label und gibt die seit dem Start verstrichene Zeit aus.
console.timeStamp(label?)
Protokolliert einen Zeitstempel mit dem angegebenen label. Kann in der Konsole oder einer Zeitachse protokolliert werden.

Die Unterstützung auf verschiedenen Plattformen ist in der folgenden Tabelle angegeben:

ChromeFirebugFirefoxIENode.jsSafari

markTimeline

profile

(devtools)

profileEnd

(devtools)

time

timeEnd

timeStamp

markTimeline wurde kursiv gesetzt, da es nur auf einer einzigen Plattform unterstützt wird. Die Bezeichnung (devtools) bedeutet, dass die Entwicklertools geöffnet sein müssen, damit die Methode funktioniert.[19]

Namensräume und spezielle Werte

Die folgenden globalen Variablen dienen als Namensräume für Funktionen. Details finden Sie im in Klammern angegebenen Material:

JSON
JSON-API-Funktionalität (Kapitel 22)
Math
Math-API-Funktionalität (Kapitel 21)
Object
Metaprogrammierungsfunktionalität (Spickzettel: Arbeiten mit Objekten)

Die folgenden globalen Variablen enthalten spezielle Werte. Für weitere Informationen lesen Sie das in Klammern angegebene Material:

undefined

Ein Wert, der ausdrückt, dass etwas nicht existiert (undefined und null)

> ({}.foo) === undefined
true
NaN

Ein Wert, der ausdrückt, dass etwas „keine Zahl“ ist (NaN)

> 1 / 'abc'
NaN
Infinity

Ein Wert, der die numerische Unendlichkeit ∞ bezeichnet (Infinity)

> 1 / 0
Infinity



[18] Mariusz Nowak (@medikoo) hat mir mitgeteilt, dass Code, der von Function ausgewertet wird, standardmäßig Sloppy ist, und zwar überall.

[19] Dank an Matthias Reuter (@gweax) und Philipp Kyeck (@pkyeck), die zu diesem Abschnitt beigetragen haben.

Weiter: 24. Unicode und JavaScript