Gibt es einen Unterschied zwischen der Deklaration einer Variablen:
var a=0; //1
...diesen Weg:
a=0; //2
...oder:
window.a=0; //3
im globalen Geltungsbereich?
javascript
Dan
quelle
quelle
Antworten:
Ja, es gibt ein paar Unterschiede, obwohl sie in der Praxis normalerweise nicht groß sind.
Es gibt einen vierten Weg und ab ES2015 (ES6) gibt es zwei weitere. Ich habe den vierten Weg am Ende hinzugefügt, aber die ES2015-Wege nach # 1 eingefügt (Sie werden sehen warum), also haben wir:
Diese Aussagen erklärt
# 1
var a = 0;
Dadurch wird eine globale Variable erstellt, die auch eine Eigenschaft des globalen Objekts ist , auf das wir als zugreifen
window
in Browsern (oder überthis
einen globalen Bereich in nicht striktem Code). Im Gegensatz zu einigen anderen Eigenschaften kann die Eigenschaft nicht über entfernt werdendelete
.In Spezifikation Bedingungen schafft sie eine Kennung Bindung an das Objekt Umgebungsdatensatz für die globale Umwelt . Dies macht es zu einer Eigenschaft des globalen Objekts, da im globalen Objekt Bezeichnerbindungen für den Objektumgebungsdatensatz der globalen Umgebung gespeichert sind. Aus diesem Grund kann die Eigenschaft nicht gelöscht werden: Es handelt sich nicht nur um eine einfache Eigenschaft, sondern um eine Bezeichnerbindung.
Die Bindung (Variable) wird definiert, bevor die erste Codezeile ausgeführt wird (siehe "Wann
var
passiert" weiter unten).Beachten Sie, dass in IE8 und früheren Versionen die am erstellte Eigenschaft
window
nicht aufzählbar ist (nicht in angezeigt wird)for..in
Anweisungen ). In IE9, Chrome, Firefox und Opera ist es aufzählbar.# 1.1
let a = 0;
Dadurch wird eine globale Variable erstellt keine Eigenschaft des globalen Objekts ist. Dies ist eine neue Sache ab ES2015.
In Bezug auf die Spezifikation wird eine Bezeichnerbindung für den deklarativen Umgebungsdatensatz für die globale Umgebung und nicht für den Objektumgebungsdatensatz erstellt . Die globale Umwelt ist einzigartig eine geteilte Umwelt Record, eine für alle alten Sachen in aufweist, der (die auf das globale Objekt geht Objekt Environment Record) und eine für alle neuen Sachen (
let
,const
und die erstellten Funktionenclass
) , die nicht zu tun gehe auf das globale Objekt.Die Bindung wird erstellt, bevor ein schrittweiser Code in seinem umschließenden Block ausgeführt wird (in diesem Fall, bevor ein globaler Code ausgeführt wird). Sie ist jedoch in keiner Weise zugänglich , bis die schrittweise Ausführung die
let
Anweisung erreicht. Sobald die Ausführung dielet
Anweisung erreicht hat, kann auf die Variable zugegriffen werden. (Siehe "Wannlet
undconst
passiert" weiter unten.)# 1.2
const a = 0;
Erstellt eine globale Konstante, die keine Eigenschaft des globalen Objekts ist.
const
ist genau so,let
außer dass Sie einen Initialisierer (das= value
Teil) bereitstellen müssen und den Wert der Konstante nach ihrer Erstellung nicht mehr ändern können. Unter der Decke ist es genau so,let
aber mit einem Flag auf der Bezeichnerbindung, das besagt, dass sein Wert nicht geändert werden kann. Verwendenconst
macht drei Dinge für Sie:# 2
a = 0;
Dadurch wird implizit eine Eigenschaft für das globale Objekt erstellt . Da es sich um eine normale Eigenschaft handelt, können Sie sie löschen. Ich würde empfehlen , dies nicht zu tun. Es kann für jeden, der Ihren Code später liest, unklar sein. Wenn Sie den strengen Modus von ES5 verwenden, ist dies ein Fehler (Zuweisen zu einer nicht vorhandenen Variablen). Dies ist einer von mehreren Gründen, den strengen Modus zu verwenden.
Interessanterweise wurde die in IE8 und früheren Versionen erstellte Eigenschaft nicht aufzählbar erstellt (wird in
for..in
Anweisungen nicht angezeigt ). Das ist seltsam, besonders angesichts der Nummer 3 unten.#3
window.a = 0;
Dadurch wird explizit eine Eigenschaft für das globale Objekt erstellt, wobei die
window
globale Eigenschaft verwendet wird, die sich auf das globale Objekt bezieht (in Browsern; einige Nicht-Browser-Umgebungen verfügen über eine äquivalente globale Variable, z. B.global
in NodeJS). Da es sich um eine normale Eigenschaft handelt, können Sie sie löschen.Diese Eigenschaft ist in IE8 und früheren Versionen sowie in jedem anderen Browser, den ich ausprobiert habe, aufzählbar.
# 4
this.a = 0;
Genau wie # 3, außer dass wir das globale Objekt
this
anstelle des globalen Objekts referenzierenwindow
. Dies funktioniert jedoch im strengen Modus nicht, da der globale Code im strengen Modusthis
keinen Verweis auf das globale Objekt hat (undefined
stattdessen hat er den Wert ).Eigenschaften löschen
Was meine ich mit "Löschen" oder "Entfernen"
a
? Genau das: Entfernen der Eigenschaft (vollständig) über dasdelete
Schlüsselwort:delete
Entfernt eine Eigenschaft vollständig aus einem Objekt. Sie können nicht tun, mit Eigenschaften hinzugefügtwindow
über indirektvar
, diedelete
entweder stillschweigend ignoriert oder lösen eine Ausnahme (abhängig von der JavaScript - Implementierung und ob Sie im strikten Modus sind).Warnung : IE8 erneut (und vermutlich früher, und IE9-IE11 im fehlerhaften "Kompatibilitäts" -Modus): Sie können die Eigenschaften des
window
Objekts nicht löschen , selbst wenn dies zulässig sein sollte. Schlimmer noch, es wird eine Ausnahme ausgelöst, wenn Sie es versuchen ( versuchen Sie dieses Experiment in IE8 und in anderen Browsern). Wenn Sie also aus demwindow
Objekt löschen , müssen Sie defensiv sein:Dadurch wird versucht, die Eigenschaft zu löschen. Wenn eine Ausnahme ausgelöst wird, wird das nächstbeste ausgeführt und die Eigenschaft auf gesetzt
undefined
.Dies gilt nur für das
window
Objekt und (soweit ich weiß) nur für IE8 und früher (oder IE9-IE11 im fehlerhaften "Kompatibilitätsmodus"). Andere Browser könnenwindow
nach den oben genannten Regeln problemlos Eigenschaften löschen .Wann
var
passiertDie über die
var
Anweisung definierten Variablen werden erstellt, bevor ein schrittweiser Code im Ausführungskontext ausgeführt wird. Daher existiert die Eigenschaft weit vor dervar
Anweisung.Dies kann verwirrend sein. Schauen wir uns also Folgendes an:
Live-Beispiel:
Code-Snippet anzeigen
Wie Sie sehen können, wird das Symbol
foo
vor der ersten Zeile definiert, das Symbolbar
jedoch nicht. Wo sich dievar foo = "f";
Anweisung befindet, gibt es zwei Dinge: Definieren des Symbols, bevor die erste Codezeile ausgeführt wird; und Zuweisen zu diesem Symbol, was geschieht, wenn sich die Linie im schrittweisen Ablauf befindet. Dies wird als "var
Heben" bezeichnet, da dasvar foo
Teil an die Oberseite des Oszilloskops verschoben ("gehoben") wird, dasfoo = "f"
Teil jedoch an seiner ursprünglichen Position belassen wird. (Siehe Schlechtes Missverständnisvar
in meinem anämischen kleinen Blog.)Wann
let
undconst
passierenlet
undconst
unterscheiden sichvar
in vielerlei Hinsicht. Die Art und Weise, auf die Frage relevant ist , ist , dass , obwohl die Bindung sie definieren , erstellt vor jedem Schritt- für -Schritt - Code ausgeführt wird , ist es nicht zugänglich , bis dielet
oderconst
Anweisung erreicht ist.Also, während dies läuft:
Dies wirft einen Fehler aus:
Die anderen beiden Arten, die sich von denen unterscheiden
let
und für die Frage nicht wirklich relevant sind, sind:const
var
var
immer gilt für den gesamten Ausführungskontext ( im gesamten globalen Code oder im gesamten Funktionscode in der Funktion , wo es angezeigt wird ), aberlet
undconst
gelten nur innerhalb des Blockes , wo sie angezeigt werden . Das heißt,var
hat die Funktion (oder global) Umfang, sondernlet
undconst
Block Umfang hat.Das Wiederholen
var a
im selben Kontext ist harmlos, aber wenn Sielet a
(oderconst a
) haben, ist es ein Syntaxfehler , ein andereslet a
oder einconst a
oder ein zu habenvar a
.Hier ist ein Beispiel, das dies demonstriert
let
undconst
sofort in ihrem Block wirksam wird, bevor Code in diesem Block ausgeführt wird, auf den jedoch erst mit der Anweisunglet
oderconst
zugegriffen werden kann:Beachten Sie, dass die zweite
console.log
fehlschlägt, anstatta
von außerhalb des Blocks auf die zuzugreifen .Off-Topic: Vermeiden Sie Unordnung im globalen Objekt (
window
)Das
window
Objekt wird sehr, sehr voll mit Eigenschaften. Wenn immer möglich, empfehlen wir dringend, das Chaos nicht zu vergrößern. Wickeln Sie stattdessen Ihre Symbole in ein kleines Paket und exportieren Sie höchstens ein Symbol in daswindow
Objekt. (Ich exportiere häufig keine Symbole in daswindow
Objekt.) Sie können eine Funktion verwenden, um Ihren gesamten Code zu enthalten, um Ihre Symbole zu enthalten, und diese Funktion kann anonym sein, wenn Sie möchten:In diesem Beispiel definieren wir eine Funktion und lassen sie sofort ausführen (
()
am Ende).Eine auf diese Weise verwendete Funktion wird häufig als Scoping-Funktion bezeichnet . Funktionen definiert innerhalb der Scoping - Funktion kann den Zugriff Variablen in der Scoping - Funktion definiert , weil sie Schließungen über diese Daten (siehe: Verschlüsse sind nicht kompliziert auf meinem anämisch kleinen Blog).
quelle
window['a']=0
, dass ich Fenster als Karte verwende? ist etwaswindow
Besonderes, so dass einige Browser dies nicht zulassen und mich zur Verwendung zwingenwindow.a
?window.a = 0;
nur in Browserumgebungen und nur gemäß Konvention. Das Binden des globalen Objekts an eine Variable mit dem Namenwindow
befindet sich nicht in der ES-Spezifikation und funktioniert daher nicht in beispielsweise V8 oder Node.js, währendthis.a = 0;
(wenn es im globalen Ausführungskontext aufgerufen wird) in jeder Umgebung funktioniert , da die Spezifikation dies angibt dass es ein globales Objekt geben muss . Wenn Sie Ihren Code wie im Abschnitt Off-Topic in ein IIFE einbinden , können Sie ihnthis
als Parameter mit dem Namenwindow
oderglobal
als direkten Verweis auf das globale Objekt übergeben.var a = 0;
wird also automatisch zu einer Eigenschaft des globalen Objekts. Wenn ichvar b = 0;
innerhalb einer Funktionsdeklaration deklariere , ist dies auch eine Eigenschaft eines zugrunde liegenden Objekts?Einfach halten:
Der obige Code gibt eine globale Bereichsvariable an
Dieser Code gibt eine Variable an, die im aktuellen Bereich und darunter verwendet werden soll
Dies entspricht im Allgemeinen der globalen Variablen.
quelle
a
unter dem nicht verwenden können aktueller Geltungsbereich. Sie können. Außerdem ist Ihre Verwendung von "globaler Variable" etwas abwegig - die beiden Stellen, an denen Sie "globale Variable" sagen, sind nicht globaler als die Stelle, an der Sie es nicht sagen.Gibt es ein globales Objekt, an dem standardmäßig alle Variablen hängen? zB: 'globals.noVar-Deklaration'
quelle
window.*
Deklaration. Diese Deklaration sieht am sichersten gegen das Kopieren und Einfügen Ihres Codes aus und ist auch klar.Gestützt auf die exzellente Antwort von TJ Crowder : ( Off-Topic: Vermeiden Sie Unordnung
window
)Dies ist ein Beispiel für seine Idee:
Html
init.js (Basierend auf dieser Antwort )
script.js
Hier ist die plnkr . Hoffe es hilft!
quelle
Im globalen Bereich gibt es keinen semantischen Unterschied.
Sie sollten dies jedoch unbedingt vermeiden,
a=0
da Sie einen Wert für eine nicht deklarierte Variable festlegen.Verwenden Sie auch Verschlüsse, um die Bearbeitung des globalen Bereichs überhaupt zu vermeiden
Verwenden Sie immer Verschlüsse und heben Sie immer den globalen Geltungsbereich an, wenn dies unbedingt erforderlich ist. Sie sollten ohnehin für den größten Teil Ihrer Kommunikation die asynchrone Ereignisbehandlung verwenden.
Wie @AvianMoncellor erwähnt hat, gibt es einen IE-Fehler, bei dem
var a = foo
nur ein globaler Dateibereich deklariert wird. Dies ist ein Problem mit dem berüchtigten kaputten Interpreter des IE. Dieser Fehler kommt mir bekannt vor, daher ist er wahrscheinlich wahr.Also bleib bei
window.globalName = someLocalpointer
quelle
delete
avar
).var
. Es sind nur völlig unterschiedliche Mechanismen, die fast das gleiche praktische Ergebnis haben. :-)var
das zum Stillstand kommt.