O que significa que o namespace global seria poluído?

92

O que significa que o namespace global seria poluído?

Eu realmente não entendo o que significa um namespace global ficar poluído.

theJava
fonte
1
Link para referência futura: Declaração de namespace JavaScript
blong

Respostas:

124

Nota rápida sobre coleta de lixo

À medida que as variáveis ​​perdem o escopo, elas se qualificam para a coleta de lixo. Se eles tiverem escopo global, eles não serão elegíveis para coleta até que o namespace global perca o escopo.

Aqui está um exemplo:

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

Adicionar isso ao seu namespace global (pelo menos para mim) deve adicionar 10.000 kb de uso de memória (win7 firefox), que não será coletado. Outros navegadores podem lidar com isso de forma diferente.

Considerando que ter o mesmo código em um escopo que sai do escopo como este:

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

Permitirá arraperder o escopo após a execução do fechamento e será elegível para a coleta de lixo.

Namespace global é seu amigo

Apesar das muitas reclamações contra o uso do namespace global, ele é seu amigo. E como um bom amigo, você não deve abusar de seu relacionamento.

Seja gentil

Não abuse (geralmente referido como "poluente") do namespace global. E o que quero dizer com não abuse do namespace global é - não crie múltiplas variáveis ​​globais. Aqui está um exemplo ruim de uso do namespace global.

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

Isso vai criar 11 variáveis ​​globais que podem ser substituídas ou mal interpretadas em algum lugar.

Seja engenhoso

Uma abordagem mais engenhosa, que não polui o namespace global, seria envolver tudo isso no padrão do módulo e usar apenas uma variável global ao expor várias variáveis.

Aqui está um exemplo: (observe que isso é simples e não há tratamento de erros)

//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());
})();
Travis J
fonte
10
manter as variáveis ​​dentro de um encerramento garante que sejam coletadas como lixo.
theJava
2
Resposta muito interessante, você pode nos explicar qual é a diferença entre usar um retorno como você fez no seu escopo, e usar, por exemplo, Calculate.prototype.Slope()fora do escopo? Seria muito perfeito compreender outro conceito próximo a esta problemática!
Ludo de
Obrigado por essa boa explicação. Pergunta rápida: o que você gostaria de ver sobre o tratamento de erros nesse snippet?
Sentenza de
@Sentenza - Depende do que aconteceria se houvesse um erro na linha. Se nada, então ele realmente não precisa de tratamento de erros. Se for importante, talvez alguns testes para garantir que a divisão por 0 não aconteça e uma mensagem ou resposta para indicar uma tentativa falhada (às vezes, isso significa apenas uma falha silenciosa). Talvez alguns testes para se certificar de que os números são realmente números e não texto. No geral, porém, o tratamento de erros depende também de quem está usando o código. Se for apenas você, você provavelmente saberá que não deve passar alguns argumentos decisivos. Este também é um exemplo bastante simples :)
Travis J
20

Em JavaScript, as declarações fora de uma função estão no escopo global. Considere este pequeno exemplo:

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

No exemplo acima, xé declarado no escopo global. Qualquer escopo filho, como aquele criado pela examplefunção, herda efetivamente coisas declaradas em qualquer escopo pai (neste caso, é apenas o escopo global).

Qualquer escopo filho que declara novamente uma variável declarada no escopo global irá sombrear a variável global, potencialmente causando bugs indesejados e difíceis de rastrear:

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

Variáveis ​​globais geralmente não são recomendadas devido ao potencial de causar problemas como este. Se não usássemos a varinstrução dentro da examplefunção, teríamos substituído acidentalmente o valor de xno escopo global:

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

Se você quiser ler mais e entendê-lo corretamente, sugiro passar pela especificação ECMAScript . Pode não ser a mais emocionante das leituras, mas não terá fim.

James Allardice
fonte
8

Quando você declara variáveis ​​globais, funções, etc., elas, ehm, vão para o namespace global. Além de problemas de desempenho / memória (que podem surgir), é provável que você se depare com conflitos de nomes infelizes, quando redefinir uma variável importante ou não usar o valor que pensa usar.

Definir coisas no namespace global deve ser evitado.

Sergio Tulentsev
fonte
1
Uma maneira de evitar definir coisas no namespace global é usar variáveis ​​locais (declaradas com "var" dentro de uma função), mas então a variável é ... local para a função. Isso deve ser feito tanto quanto possível.
Stéphane Glondu