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?
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?
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:
var a = 0; // 1
let a = 0; // 1.1 (new with ES2015)
const a = 0; // 1.2 (new with ES2015)
a = 0; // 2
window.a = 0; // 3
this.a = 0; // 4
# 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 windoww przeglądarkach (lub za pośrednictwem thiszasię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średnictwem delete.
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ę varstanie” poniżej).
Zauważ, że w IE8 i wcześniejszych utworzona właściwość windownie jest wyliczalna (nie pojawia się w for..ininstrukcjach). 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, consti funkcje stworzone przez class), 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 letinstrukcji. Gdy wykonanie osiągnie letinstrukcję, zmienna jest dostępna. (Zobacz „Kiedy leti co się conststanie” poniżej.)
# 1.2 const a = 0;
Tworzy stałą globalną, która nie jest własnością obiektu globalnego.
constjest dokładnie tak samo, letz tym wyjątkiem, że musisz podać inicjator ( = valueczęść) i nie możesz zmienić wartości stałej po jej utworzeniu. Pod okładkami jest dokładnie tak, letale z flagą na identyfikatorze wiążącą, że jego wartości nie można zmienić. Korzystanie constrobi 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..ininstrukcjach). 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 windowglobalnego, 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ład globalNodeJS). 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 thiszamiast globalnego window. Nie działa to jednak w trybie ścisłym, ponieważ w trybie ścisłym kod globalny thisnie ma odniesienia do obiektu globalnego ( undefinedzamiast tego ma wartość ).
Co rozumiem przez „usuwanie” lub „usuwanie” a? Dokładnie to: usunięcie właściwości (całkowicie) za pomocą deletesłowa kluczowego:
window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"
deletecałkowicie usuwa właściwość z obiektu. Nie możesz tego zrobić z właściwościami dodanymi windowpośrednio przez var, deletealbo 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 windowobiektu, 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ąc windowobiekt, musisz być defensywny:
try {
delete window.prop;
}
catch (e) {
window.prop = undefined;
}
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 windowobiektu 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ć windowwłaściwości zgodnie z powyższymi zasadami.
varstanieZmienne zdefiniowane przez varoświadczenia są tworzone przed każdy prowadzony jest kod krok po kroku w kontekście realizacji, a więc własność istnieje dobrze przed tym varstwierdzeniem.
Może to być mylące, więc spójrzmy:
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar); // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar); // displays "b"
Przykład na żywo:
Jak widać, symbol foojest zdefiniowany przed pierwszą linią, ale symbol barnie jest. Tam, gdzie var 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 „ varpodnoszeniem”, ponieważ var fooczęść jest przenoszona („podnoszona”) na szczyt zakresu, ale foo = "f"część pozostaje w pierwotnym położeniu. (Zobacz Biedny źle zrozumianyvar na moim anemicznym małym blogu.)
leti się constzdarzyleti constróżnią się od siebie varna 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 instrukcja letlub const.
Podczas gdy to działa:
display(a); // undefined
var a = 0;
display(a); // 0
To powoduje błąd:
display(a); // ReferenceError: a is not defined
let a = 0;
display(a);
Pozostałe dwa sposoby, leta constróżnią się var, co tak naprawdę nie są istotne z punktu widzenia pytanie, to:
varzawsze odnosi się do całego kontekstu wykonania (w całym kodzie globalnym, lub całej kodu funkcji w zależności gdzie się pojawia), ale leti conststosować tylko w bloku , w którym się pojawiają. Oznacza to, że varposiada funkcję (lub globalne) zakres, ale leti constmieć zakres bloku.
Powtarzanie var aw tym samym kontekście jest nieszkodliwe, ale jeśli masz let a(lub const a), posiadanie innego let alub a const alub a var ajest błędem składni.
Oto przykład, który to pokazuje leti conststosuje się natychmiast w ich bloku, zanim uruchomi się jakikolwiek kod w tym bloku, ale nie są one dostępne, dopóki instrukcja letlub const:
var a = 0;
console.log(a);
if (true)
{
console.log(a); // ReferenceError: a is not defined
let a = 1;
console.log(a);
}
Zauważ, że drugi console.logkończy się niepowodzeniem, zamiast uzyskiwać dostęp az zewnątrz bloku.
window)windowObiekt 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 do windowobiektu. (Często nie eksportuję żadnych symboli do windowobiektu.) 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:
(function() {
var a = 0; // `a` is NOT a property of `window` now
function foo() {
alert(a); // Alerts "0", because `foo` can access `a`
}
})();
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).
window['a']=0aby wyjaśnić, że używam okna jako mapy? jest windowwyjątkowy, ponieważ niektóre przeglądarki na to nie pozwalają i zmuszają mnie do używania window.a?
window.a = 0;działa tylko w środowiskach przeglądarki i tylko zgodnie z konwencją. Wiązania globalnego obiektu do zmiennej o nazwie windownie jest w ES Spec i tak nie będzie działać w, na przykład, V8 lub node.js, podczas gdy this.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. thiswindowglobal
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:
a = 0
Powyższy kod podaje globalną zmienną zakresu
var a = 0;
Ten kod da zmienną do użycia w bieżącym zakresie i pod nim
window.a = 0;
Zasadniczo jest to to samo co zmienna globalna.
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.
<title>Index.html</title>
<script>
var varDeclaration = true;
noVarDeclaration = true;
window.hungOnWindow = true;
document.hungOnDocument = true;
</script>
<script src="external.js"></script>
/* external.js */
console.info(varDeclaration == true); // could be .log, alert etc
// returns false in IE8
console.info(noVarDeclaration == true); // could be .log, alert etc
// returns false in IE8
console.info(window.hungOnWindow == true); // could be .log, alert etc
// returns true in IE8
console.info(document.hungOnDocument == true); // could be .log, alert etc
// returns ??? in IE8 (untested!) *I personally find this more clugy than hanging off window obj
Czy istnieje obiekt globalny, z którego domyślnie są zawieszone wszystkie zmienary? np .: „deklaracja globals.noVar”
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łaganuwindow )
Oto przykład jego pomysłu:
HTML
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript">
MYLIBRARY.init(["firstValue", 2, "thirdValue"]);
</script>
<script src="script.js"></script>
</head>
<body>
<h1>Hello !</h1>
</body>
</html>
init.js (na podstawie tej odpowiedzi )
var MYLIBRARY = MYLIBRARY || (function(){
var _args = {}; // private
return {
init : function(Args) {
_args = Args;
// some other initialising
},
helloWorld : function(i) {
return _args[i];
}
};
}());
script.js
// Here you can use the values defined in the html as if it were a global variable
var a = "Hello World " + MYLIBRARY.helloWorld(2);
alert(a);
Oto plnkr . Mam nadzieję, że to pomoże!
W zakresie globalnym nie ma różnicy semantycznej.
Ale naprawdę powinieneś unikać, a=0ponieważ ustawiasz wartość na niezadeklarowaną zmienną.
Użyj również zamknięć, aby w ogóle uniknąć edytowania zasięgu globalnego
(function() {
// do stuff locally
// Hoist something to global scope
window.someGlobal = someLocal
}());
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 = foodeklaruje 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
deletevar
var. Są to po prostu zupełnie inne mechanizmy, które mają bardzo podobny praktyczny wynik. :-)
varprzeskakuje do końca zakresu.