Що означає глобальний простір імен буде забрудненим?


Відповіді:


124

Коротка примітка про збір сміття

Оскільки змінні втрачають обсяг, вони зможуть збирати сміття. Якщо їх масштабують у всьому світі, вони не матимуть права на збір, доки глобальний простір імен не втратить сферу дії.

Ось приклад:

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

Додавання цього у ваш глобальний простір імен (принаймні для мене) має забезпечити 10 000 кб використання пам'яті (win7 firefox), яке не збиратиметься. Інші браузери можуть обробляти це по-різному.

Тоді як наявність того самого коду в області, яка виходить за рамки такої форми:

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

Дозволить arraвтратити обсяг після закриття та мати право на вивезення сміття.

Глобальний простір імен - ваш друг

Незважаючи на багато претензій до використання глобального простору імен, це ваш друг. І як добрий друг, не слід зловживати своїми стосунками.

Будь ніжним

Не зловживайте (зазвичай називають "забруднюючим") глобальним простором імен. І що я маю на увазі, не зловживаючи глобальним простором імен, - не створюйте кілька глобальних змінних. Ось поганий приклад використання глобального простору імен.

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);

Це збирається створити 11 глобальних змінних, які, можливо, можуть бути десь переписані або неправильно витлумачені.

Будь винахідливим

Більш винахідливим підходом, який не забруднює глобальний простір імен, було б обернути все це шаблоном модуля і використовувати лише одну глобальну змінну, оголюючи кілька змінних.

Ось приклад: (Будь ласка, зверніть увагу, що це просто, і помилок не обробляється)

//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
зберігання змінних всередині закриття гарантує, що вони збирають сміття.
theJava

2
Дуже цікава відповідь, чи можете ви пояснити нам, в чому різниця між використанням повернення, як це було у вашому обсязі, і використанням, наприклад, Calculate.prototype.Slope()поза обсягом? Було б ідеально зрозуміти ще одну концепцію, близьку до цієї проблематики!
Людо

Дякую за це гарне пояснення. Швидке запитання: Що б ви хотіли бачити щодо обробки помилок у цьому фрагменті?
Sentenza

@Sentenza - Це залежить від того, що сталося б, якби сталася помилка. Якщо нічого, то справді не потребує обробки помилок. Якщо це важливо, то, можливо, деякі тести, щоб переконатися, що ділення на 0 не відбувається, і повідомлення чи відповідь, що вказують на невдалу спробу (іноді це просто означає тиху невдачу). Можливо, деякі тести, щоб переконатися, що цифри насправді є цифрами, а не текстом. Загалом, опрацювання помилок також залежить від того, хто використовує код. Якщо це лише ви, ви, мабуть, знатимете, що не слід передавати певні важливі аргументи. Це також досить простий приклад :)
Тревіс Дж.

20

У JavaScript декларації поза функцією знаходяться в глобальній області. Розглянемо цей невеликий приклад:

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

У наведеному вище прикладі xоголошено в глобальній області. Будь-яка дочірня область, така як створена exampleфункцією, фактично успадковує речі, заявлені в будь-яких батьківських областях (у цьому випадку це лише глобальна сфера).

Будь-яка дочірня область, яка повторно оголошує змінну, оголошену в глобальній області, буде затінювати глобальну змінну, що потенційно може спричинити небажані, важко відстежувані помилки:

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

Глобальні змінні зазвичай не рекомендуються, оскільки вони можуть спричинити подібні проблеми. Якби ми не використовували varоператор усередині exampleфункції, ми б випадково перезаписали значення xв глобальній області:

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

Якщо ви хочете прочитати більше та зрозуміти це належним чином, я пропоную пройти специфікацію ECMAScript . Це може бути не найзахоплююче читання, але це не допоможе кінцю.


8

Коли ви оголошуєте глобальні змінні, функції тощо, вони, е-е, переходять до глобального простору імен. Окрім проблем із продуктивністю / пам'яттю (які можуть виникнути), ви, швидше за все, зіткнетеся з прикрим зіткненням назв, коли ви перевизначите важливу змінну або використаєте не значення, яке, на вашу думку, використовуєте.

Варто уникати визначення речей у глобальному просторі імен.


1
Спосіб уникнути визначення речей у глобальному просторі імен полягає у використанні локальних змінних (оголошених "var" усередині функції), але тоді змінна є ... локальною для функції. Це слід робити якомога більше.
Стефан Глонду
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.