Что это означает, что глобальное пространство имен будет загрязнено?

92

Что это означает, что глобальное пространство имен будет загрязнено?

Я действительно не понимаю, что означает загрязнение глобального пространства имен.

theJava
источник
1
Связывание для использования в будущем: Объявление пространства имен JavaScript
blong

Ответы:

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()вне области действия? Было бы прекрасно понять другую концепцию, близкую к этой проблематике!
Ludo
Спасибо за хорошее объяснение. Быстрый вопрос: что бы вы хотели увидеть в этом фрагменте об обработке ошибок?
Sentenza
@Sentenza - это зависит от того, что произойдет, если в дальнейшем будет ошибка. Если ничего, значит, обработка ошибок действительно не требуется. Если это важно, то, возможно, некоторые тесты, чтобы убедиться, что деление на 0 не происходит, и сообщение или ответ, указывающие на неудачную попытку (иногда это просто означает молчаливую неудачу). Возможно, некоторые тесты, чтобы убедиться, что числа на самом деле являются числами, а не текстом. Однако в целом обработка ошибок зависит также от того, кто использует код. Если это только вы, вы, вероятно, будете знать, что нельзя передавать определенные критические аргументы. Это тоже довольно простой пример :)
Travis J
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» внутри функции), но тогда эта переменная является ... локальной для функции. Делать это нужно по возможности.
Стефан Глонду