Co to znaczy, że globalna przestrzeń nazw byłaby zanieczyszczona?


Odpowiedzi:


124

Szybka uwaga na temat zbierania śmieci

Ponieważ zmienne tracą zasięg, będą kwalifikować się do czyszczenia pamięci. Jeśli mają zasięg globalny, nie będą kwalifikować się do zbierania, dopóki globalna przestrzeń nazw nie utraci zakresu.

Oto przykład:

var arra = [];
for (var i = 0; i < 2003000; i++) {
 arra.push(i * i + i);
}

Dodanie tego do globalnej przestrzeni nazw (przynajmniej dla mnie) powinno zapewnić 10 000 kB wykorzystania pamięci (firefox win7), które nie zostaną zebrane. Inne przeglądarki mogą to obsługiwać inaczej.

Zważywszy, że posiadanie tego samego kodu w zakresie, który wykracza poza ten zakres:

(function(){
 var arra = [];
 for (var i = 0; i < 2003000; i++) {
  arra.push(i * i + i);
 }
})();

Pozwoli arrastracić zakres po wykonaniu zamknięcia i będzie kwalifikować się do czyszczenia pamięci.

Globalna przestrzeń nazw jest Twoim przyjacielem

Pomimo wielu zarzutów przeciwko używaniu globalnej przestrzeni nazw, jest to twój przyjaciel. I jak dobry przyjaciel, nie powinieneś nadużywać swojego związku.

Bądź delikatny

Nie nadużywaj (zwykle nazywanej „zanieczyszczeniem”) globalnej przestrzeni nazw. Nie nadużywaj globalnej przestrzeni nazw mam na myśli - nie twórz wielu zmiennych globalnych. Oto zły przykład użycia globalnej przestrzeni nazw.

var x1 = 5;
var x2 = 20;
var y1 = 3
var y2 = 16;

var rise = y2 - y1;
var run = x2 - x1;

var slope = rise / run;

var risesquared = rise * rise;
var runsquared = run * run;

var distancesquared = risesquared + runsquared;

var distance = Math.sqrt(dinstancesquared);

Stworzy to 11 zmiennych globalnych, które mogą zostać gdzieś nadpisane lub źle zinterpretowane.

Bądź zaradny

Bardziej pomysłowym podejściem, które nie zanieczyszcza globalnej przestrzeni nazw, byłoby zawinięcie tego wszystkiego we wzorzec modułu i użycie tylko jednej zmiennej globalnej podczas ujawniania wielu zmiennych.

Oto przykład: (Należy pamiętać, że jest to proste i nie ma obsługi błędów)

//Calculate is the only exposed global variable
var Calculate = function () {
 //all defintions in this closure are local, and will not be exposed to the global namespace
 var Coordinates = [];//array for coordinates
 var Coordinate = function (xcoord, ycoord) {//definition for type Coordinate
   this.x = xcoord;//assign values similar to a constructor
   this.y = ycoord;
  };

  return {//these methods will be exposed through the Calculate object
   AddCoordinate: function (x, y) {
   Coordinates.push(new Coordinate(x, y));//Add a new coordinate
  },

  Slope: function () {//Calculates slope and returns the value
   var c1 = Coordinates[0];
   var c2 = Coordinates[1];
   return c2.y - c1.y / c2.x - c1.x;//calculates rise over run and returns result
  },

  Distance: function () {
   //even with an excessive amount of variables declared, these are all still local
   var c1 = Coordinates[0];
   var c2 = Coordinates[1];

   var rise = c2.y - c1.y;
   var run = c2.x - c1.x;

   var risesquared = rise * rise;
   var runsquared = run * run;

   var distancesquared = risesquared + runsquared;

   var distance = Math.sqrt(distancesquared);

   return distance;
  }
 };
};

//this is a "self executing closure" and is used because these variables will be
//scoped to the function, and will not be available globally nor will they collide
//with any variable names in the global namespace
(function () {
 var calc = Calculate();
 calc.AddCoordinate(5, 20);
 calc.AddCoordinate(3, 16);
 console.log(calc.Slope());
 console.log(calc.Distance());
})();

10
trzymanie zmiennych wewnątrz zamknięcia gwarantuje, że są one zbierane jako śmieci.
Jawa

2
Bardzo interesująca odpowiedź, czy możesz nam wyjaśnić, jaka jest różnica między używaniem zwrotu, tak jak zrobiłeś to w swoim zakresie, a używaniem na przykład Calculate.prototype.Slope()poza zakresem? Byłoby doskonale zrozumieć inną koncepcję bliską tej problematyce!
Ludo,

Dzięki za to dobre wyjaśnienie. Szybkie pytanie: co chciałbyś zobaczyć na temat obsługi błędów w tym fragmencie?
Sentenza

@Sentenza - To zależy od tego, co by się stało, gdyby pojawił się błąd. Jeśli nic, to naprawdę nie wymaga obsługi błędów. Jeśli jest to ważne, być może niektóre testy, aby upewnić się, że dzielenie przez 0 nie nastąpi, i komunikat lub odpowiedź wskazująca nieudaną próbę (czasami oznacza to po prostu cichą porażkę). Być może kilka testów, aby upewnić się, że liczby są w rzeczywistości liczbami, a nie tekstem. Ogólnie rzecz biorąc, obsługa błędów zależy również od tego, kto używa kodu. Jeśli jesteś tylko ty, prawdopodobnie będziesz wiedział, że nie należy przekazywać pewnych przełomowych argumentów. To też jest raczej prosty przykład :)
Travis J

20

W JavaScript deklaracje poza funkcją znajdują się w zasięgu globalnym. Rozważ ten mały przykład:

var x = 10;
function example() {
    console.log(x);
}
example(); //Will print 10

W powyższym przykładzie xjest zadeklarowana w zakresie globalnym. Każdy zakres podrzędny, taki jak ten utworzony przez examplefunkcję, skutecznie dziedziczy rzeczy zadeklarowane w dowolnych zakresach nadrzędnych (w tym przypadku jest to tylko zasięg globalny).

Każdy zakres podrzędny, który ponownie deklaruje zmienną zadeklarowaną w zakresie globalnym, będzie cieniał zmienną globalną, potencjalnie powodując niechciane, trudne do śledzenia błędy:

var x = 10;
function example() {
    var x = 20;
    console.log(x); //Prints 20
}
example();
console.log(x); //Prints 10

Zmienne globalne zwykle nie są zalecane, ponieważ mogą powodować tego typu problemy. Gdybyśmy nie użyli varinstrukcji wewnątrz examplefunkcji, przypadkowo nadpisalibyśmy wartość xw zakresie globalnym:

var x = 10;
function example() {
    x = 20; //Oops, no var statement
    console.log(x); //Prints 20
}
example();
console.log(x); //Prints 20... oh dear

Jeśli chcesz przeczytać więcej i dobrze to zrozumieć, proponuję zapoznać się ze specyfikacją ECMAScript . Może nie jest to najbardziej ekscytująca lektura, ale pomoże to bez końca.


8

Kiedy deklarujesz zmienne globalne, funkcje itp., One, ehm, przechodzą do globalnej przestrzeni nazw. Oprócz problemów z wydajnością / pamięcią (które mogą się pojawić), prawdopodobnie napotkasz niefortunną kolizję nazw, kiedy ponownie zdefiniujesz ważną zmienną lub nie użyjesz wartości, której myślisz, że używasz.

Należy unikać definiowania elementów w globalnej przestrzeni nazw.


1
Sposobem uniknięcia definiowania rzeczy w globalnej przestrzeni nazw jest użycie zmiennych lokalnych (zadeklarowanych za pomocą „var” wewnątrz funkcji), ale wtedy zmienna jest ... lokalna dla funkcji. Należy to zrobić tak często, jak to możliwe.
Stéphane Glondu
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.