Czy istnieje jakakolwiek różnica między deklarowaniem zmiennej:
var a=0; //1
...tą drogą:
a=0; //2
...lub:
window.a=0; //3
w zasięgu globalnym?
javascript
Dan
źródło
źródło
Odpowiedzi:
Tak, istnieje kilka różnic, choć w praktyce nie są one zwykle duże.
Jest czwarty sposób, a od ES2015 (ES6) są jeszcze dwa. Na końcu dodałem czwarty sposób, ale wstawiłem ES2015 po nr 1 (zobaczysz dlaczego), więc mamy:
Te oświadczenia zostały wyjaśnione
# 1
var a = 0;
Tworzy to zmienną globalną, która jest także własnością obiektu globalnego , do którego uzyskujemy dostęp jak
window
w przeglądarkach (lub za pośrednictwemthis
zasięgu globalnego, w nieskomplikowanym kodzie). W przeciwieństwie do niektórych innych właściwości, właściwości nie można usunąć za pośrednictwemdelete
.Pod względem specyfikacji, tworzy identyfikator wiążącą na obiekcie Środowisko Record dla globalnego środowiska . To sprawia, że jest to właściwość obiektu globalnego, ponieważ obiekt globalny jest miejscem, w którym przechowywane są powiązania identyfikatorów obiektu środowiska globalnego Record Environment. Właśnie dlatego tej właściwości nie można usunąć: nie jest to zwykła właściwość, ale także powiązanie identyfikatora.
Wiązanie (zmienne) jest definiowane przed uruchomieniem pierwszego wiersza kodu (patrz „Kiedy się
var
stanie” poniżej).Zauważ, że w IE8 i wcześniejszych utworzona właściwość
window
nie jest wyliczalna (nie pojawia się wfor..in
instrukcjach). W IE9, Chrome, Firefox i Opera jest wymienny.# 1.1
let a = 0;
Tworzy to zmienną globalną, która nie jest własnością obiektu globalnego. To nowość od ES2015.
Pod względem specyfikacji tworzy identyfikator wiążący deklaratywny rekord środowiska dla środowiska globalnego, a nie obiektowy rekord środowiska. Środowisko globalny jest wyjątkowy o podział Środowisko Record, jeden za wszystkich starych rzeczy, które idzie na światowym obiektu ( obiekt Środowisko Record), a inny dla wszystkich nowych rzeczy (
let
,const
i funkcje stworzone przezclass
), które nie przejdź do obiektu globalnego.Powiązanie jest tworzone przed wykonaniem dowolnego kodu krok po kroku w jego otaczającym bloku (w tym przypadku przed uruchomieniem dowolnego kodu globalnego), ale nie jest dostępne w żaden sposób, dopóki wykonanie instrukcji krok po kroku nie osiągnie
let
instrukcji. Gdy wykonanie osiągnielet
instrukcję, zmienna jest dostępna. (Zobacz „Kiedylet
i co sięconst
stanie” poniżej.)# 1.2
const a = 0;
Tworzy stałą globalną, która nie jest własnością obiektu globalnego.
const
jest dokładnie tak samo,let
z tym wyjątkiem, że musisz podać inicjator (= value
część) i nie możesz zmienić wartości stałej po jej utworzeniu. Pod okładkami jest dokładnie tak,let
ale z flagą na identyfikatorze wiążącą, że jego wartości nie można zmienić. Korzystanieconst
robi dla Ciebie trzy rzeczy:# 2
a = 0;
Spowoduje to niejawne utworzenie właściwości obiektu globalnego . Ponieważ jest to normalna właściwość, możesz ją usunąć. Nie polecam tego robić, może być niejasne dla osób czytających Twój kod później. Jeśli używasz trybu ścisłego ES5, wykonanie tego (przypisanie do nieistniejącej zmiennej) jest błędem. Jest to jeden z kilku powodów, dla których warto stosować tryb ścisły.
Co ciekawe, ponownie w IE8 i wcześniejszych utworzona właściwość jest niepoliczalna (nie pojawia się w
for..in
instrukcjach). To dziwne, szczególnie biorąc pod uwagę nr 3 poniżej.# 3
window.a = 0;
Spowoduje to jawne utworzenie właściwości obiektu globalnego przy użyciu obiektu
window
globalnego, który odnosi się do obiektu globalnego (w przeglądarkach; niektóre środowiska inne niż przeglądarka mają równoważną zmienną globalną, na przykładglobal
NodeJS). Ponieważ jest to normalna właściwość, możesz ją usunąć.Ta właściwość jest wyliczalna w IE8 i wcześniejszych wersjach oraz w każdej innej przeglądarce, której próbowałem.
# 4
this.a = 0;
Dokładnie jak w punkcie 3, z tym wyjątkiem, że odwołujemy się do globalnego obiektu
this
zamiast globalnegowindow
. Nie działa to jednak w trybie ścisłym, ponieważ w trybie ścisłym kod globalnythis
nie ma odniesienia do obiektu globalnego (undefined
zamiast tego ma wartość ).Usuwanie właściwości
Co rozumiem przez „usuwanie” lub „usuwanie”
a
? Dokładnie to: usunięcie właściwości (całkowicie) za pomocądelete
słowa kluczowego:delete
całkowicie usuwa właściwość z obiektu. Nie możesz tego zrobić z właściwościami dodanymiwindow
pośrednio przezvar
,delete
albo jest on cicho ignorowany, albo zgłasza wyjątek (w zależności od implementacji JavaScript i tego, czy jesteś w trybie ścisłym).Ostrzeżenie : IE8 ponownie (i prawdopodobnie wcześniej, i IE9-IE11 w zepsutym trybie „kompatybilności”): Nie pozwoli ci usunąć właściwości
window
obiektu, nawet jeśli powinieneś. Co gorsza, rzuca wyjątek podczas próby ( spróbuj tego eksperymentu w IE8 i innych przeglądarkach). Więc usuwającwindow
obiekt, musisz być defensywny:Próbuje usunąć właściwość, a jeśli zostanie zgłoszony wyjątek, robi następną najlepszą rzecz i ustawia właściwość na
undefined
.Odnosi się to tylko do
window
obiektu i tylko (o ile mi wiadomo) do IE8 i wcześniejszych (lub IE9-IE11 w niedziałającym trybie „kompatybilności”). Inne przeglądarki mogą usuwaćwindow
właściwości zgodnie z powyższymi zasadami.Kiedy to się
var
stanieZmienne zdefiniowane przez
var
oświadczenia są tworzone przed każdy prowadzony jest kod krok po kroku w kontekście realizacji, a więc własność istnieje dobrze przed tymvar
stwierdzeniem.Może to być mylące, więc spójrzmy:
Przykład na żywo:
Pokaż fragment kodu
Jak widać, symbol
foo
jest zdefiniowany przed pierwszą linią, ale symbolbar
nie jest. Tam, gdzievar foo = "f";
znajduje się instrukcja, tak naprawdę są dwie rzeczy: zdefiniowanie symbolu, co dzieje się przed uruchomieniem pierwszego wiersza kodu; i wykonanie przypisania do tego symbolu, co dzieje się tam, gdzie linia przebiega krok po kroku. Nazywa się to „var
podnoszeniem”, ponieważvar foo
część jest przenoszona („podnoszona”) na szczyt zakresu, alefoo = "f"
część pozostaje w pierwotnym położeniu. (Zobacz Biedny źle zrozumianyvar
na moim anemicznym małym blogu.)Kiedy
let
i sięconst
zdarzylet
iconst
różnią się od siebievar
na kilka sposobów. Istotne dla pytania jest to, że chociaż powiązanie, które definiują, jest tworzone przed uruchomieniem kodu krok po kroku, nie jest ono dostępne, dopóki nie zostanie osiągnięta instrukcjalet
lubconst
.Podczas gdy to działa:
To powoduje błąd:
Pozostałe dwa sposoby,
let
aconst
różnią sięvar
, co tak naprawdę nie są istotne z punktu widzenia pytanie, to:var
zawsze odnosi się do całego kontekstu wykonania (w całym kodzie globalnym, lub całej kodu funkcji w zależności gdzie się pojawia), alelet
iconst
stosować tylko w bloku , w którym się pojawiają. Oznacza to, żevar
posiada funkcję (lub globalne) zakres, alelet
iconst
mieć zakres bloku.Powtarzanie
var a
w tym samym kontekście jest nieszkodliwe, ale jeśli maszlet a
(lubconst a
), posiadanie innegolet a
lub aconst a
lub avar a
jest błędem składni.Oto przykład, który to pokazuje
let
iconst
stosuje się natychmiast w ich bloku, zanim uruchomi się jakikolwiek kod w tym bloku, ale nie są one dostępne, dopóki instrukcjalet
lubconst
:Zauważ, że drugi
console.log
kończy się niepowodzeniem, zamiast uzyskiwać dostępa
z zewnątrz bloku.Off-topic: Unikaj zaśmiecania obiektu globalnego (
window
)window
Obiekt staje się bardzo, bardzo zaśmiecone właściwości. Jeśli to możliwe, zdecydowanie nie dodawaj bałaganu. Zamiast tego zawiń symbole w małą paczkę i wyeksportuj maksymalnie jeden symbol dowindow
obiektu. (Często nie eksportuję żadnych symboli dowindow
obiektu.) Możesz użyć funkcji, która zawiera cały kod w celu przechowywania symboli, a funkcja ta może być anonimowa, jeśli chcesz:W tym przykładzie definiujemy funkcję i uruchamiamy ją od razu (
()
na końcu).Używana w ten sposób funkcja jest często nazywana funkcją określania zakresu . Funkcje zdefiniowane w funkcji scoping mogą uzyskać dostęp do zmiennych zdefiniowanych w funkcji scoping, ponieważ są zamknięciami w stosunku do tych danych (patrz: Zamknięcia nie są skomplikowane na moim anemicznym blogu).
źródło
window['a']=0
aby wyjaśnić, że używam okna jako mapy? jestwindow
wyjątkowy, ponieważ niektóre przeglądarki na to nie pozwalają i zmuszają mnie do używaniawindow.a
?window.a = 0;
działa tylko w środowiskach przeglądarki i tylko zgodnie z konwencją. Wiązania globalnego obiektu do zmiennej o nazwiewindow
nie jest w ES Spec i tak nie będzie działać w, na przykład, V8 lub node.js, podczas gdythis.a = 0;
(przy wywołaniu w kontekście globalnym wykonania) będzie działać w każdym środowisku, ponieważ spec ma określić że musi istnieć globalny obiekt. W przypadku zawijania kodu w IIFE, jak w sekcji Off-topic , można przekazać jako parametr o nazwie lub uzyskać bezpośrednie odwołanie do obiektu globalnego.this
window
global
var a = 0;
automatycznie staje się własnością obiektu globalnego. Jeśli zadeklarujęvar b = 0;
w ramach deklaracji funkcji, czy będzie ona również własnością jakiegoś obiektu bazowego?Prostota:
Powyższy kod podaje globalną zmienną zakresu
Ten kod da zmienną do użycia w bieżącym zakresie i pod nim
Zasadniczo jest to to samo co zmienna globalna.
źródło
a
w ramach obecny zakres. Możesz. Ponadto użycie „zmiennej globalnej” jest nieco wyłączone - dwa miejsca, które mówisz „zmienna globalna”, nie są bardziej globalne niż miejsce, w którym nie mówisz.Czy istnieje obiekt globalny, z którego domyślnie są zawieszone wszystkie zmienary? np .: „deklaracja globals.noVar”
źródło
window.*
deklaracji. Ta deklaracja wygląda najbezpieczniej przed wklejeniem kodu, a także wyczyścić.Na podstawie doskonałej odpowiedzi TJ Crowder : ( Off-topic: Unikaj bałaganu
window
)Oto przykład jego pomysłu:
HTML
init.js (na podstawie tej odpowiedzi )
script.js
Oto plnkr . Mam nadzieję, że to pomoże!
źródło
W zakresie globalnym nie ma różnicy semantycznej.
Ale naprawdę powinieneś unikać,
a=0
ponieważ ustawiasz wartość na niezadeklarowaną zmienną.Użyj również zamknięć, aby w ogóle uniknąć edytowania zasięgu globalnego
Zawsze używaj zamknięć i zawsze podnoś do globalnego zasięgu, gdy jest to absolutnie konieczne. Tak czy inaczej, przez większość komunikacji powinieneś używać asynchronicznej obsługi zdarzeń.
Jak wspomniano @AvianMoncellor, istnieje błąd IE, który
var a = foo
deklaruje jedynie globalny zasięg pliku. Jest to problem z notorycznie zepsutym tłumaczem IE. Ten błąd brzmi znajomo, więc prawdopodobnie jest to prawda.Więc trzymaj się
window.globalName = someLocalpointer
źródło
delete
var
var
. Są to po prostu zupełnie inne mechanizmy, które mają bardzo podobny praktyczny wynik. :-)var
przeskakuje do końca zakresu.