Qu'est-ce que cela signifie que l'espace de noms global serait pollué?

92

Qu'est-ce que cela signifie que l'espace de noms global serait pollué?

Je ne comprends pas vraiment ce que signifie l'espace de noms global pollué.

theJava
la source
1
Lien pour référence future: Déclaration d'espace de noms JavaScript
blong

Réponses:

124

Note rapide sur la collecte des ordures

À mesure que les variables perdent de leur portée, elles seront éligibles pour le garbage collection. S'ils sont étendus globalement, ils ne seront pas éligibles pour la collection tant que l'espace de noms global n'aura pas perdu sa portée.

Voici un exemple:

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

L'ajout de cela à votre espace de noms global (du moins pour moi) devrait ajouter 10 000 Ko d'utilisation de la mémoire (win7 firefox) qui ne seront pas collectés. D'autres navigateurs peuvent gérer cela différemment.

Alors que d'avoir ce même code dans une portée qui sort du champ d'application comme ceci:

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

Permettra arrade perdre de la portée après l'exécution de la fermeture et sera éligible pour le ramasse-miettes.

L'espace de noms global est votre ami

Malgré les nombreuses réclamations contre l'utilisation de l'espace de noms global, c'est votre ami. Et comme un bon ami, vous ne devez pas abuser de votre relation.

Sois gentil

N'abusez pas (généralement appelé «polluant») de l'espace de noms global. Et ce que je veux dire par ne pas abuser de l'espace de noms global, c'est - ne pas créer plusieurs variables globales. Voici un mauvais exemple d'utilisation de l'espace de noms 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);

Cela va créer 11 variables globales qui pourraient éventuellement être écrasées ou mal interprétées quelque part.

Soyez ingénieux

Une approche plus ingénieuse, qui ne pollue pas l'espace de noms global, consisterait à envelopper tout cela dans le modèle de module et à n'utiliser qu'une seule variable globale tout en exposant plusieurs variables.

Voici un exemple: (Veuillez noter que c'est simple et qu'il n'y a pas de gestion des erreurs)

//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
la source
10
garder les variables à l'intérieur d'une fermeture garantit qu'elles sont ramassées.
theJava
2
Réponse très intéressante, pouvez-vous nous expliquer quelle est la différence entre l'utilisation d'un retour comme vous l'avez fait dans votre périmètre, et l'utilisation par exemple Calculate.prototype.Slope()hors du périmètre? Il serait très parfait de comprendre un autre concept proche de cette problématique!
Ludo
Merci pour cette bonne explication. Question rapide: que souhaiteriez-vous voir sur la gestion des erreurs dans cet extrait de code?
Sentenza
@Sentenza - Cela dépend de ce qui se passerait s'il y avait une erreur sur toute la ligne. Si rien, alors il n'a vraiment pas besoin de gestion des erreurs. Si c'est important, alors peut-être quelques tests pour s'assurer que la division par 0 ne se produit pas, et un message ou une réponse pour indiquer une tentative ratée (parfois cela signifie simplement un échec silencieux). Peut-être quelques tests pour s'assurer que les nombres sont en fait des nombres et non du texte. Dans l'ensemble cependant, la gestion des erreurs dépend également de la personne qui utilise le code. Si ce n'est que vous, vous saurez probablement ne pas passer certains arguments de rupture. C'est aussi un exemple assez simple :)
Travis J
20

En JavaScript, les déclarations en dehors d'une fonction sont dans la portée globale. Prenons ce petit exemple:

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

Dans l'exemple ci-dessus, xest déclaré dans la portée globale. Toute portée enfant, telle que celle créée par la examplefonction, hérite effectivement des éléments déclarés dans toutes les portées parent (dans ce cas, il ne s'agit que de la portée globale).

Toute portée enfant qui redéclarera une variable déclarée dans la portée globale occultera la variable globale, provoquant potentiellement des bogues indésirables et difficiles à suivre:

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

Les variables globales ne sont généralement pas recommandées en raison du potentiel de causer des problèmes comme celui-ci. Si nous n'avions pas utilisé l' varinstruction dans la examplefonction, nous aurions accidentellement écrasé la valeur de xdans la portée globale:

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

Si vous voulez en savoir plus et le comprendre correctement, je vous suggère de passer par la spécification ECMAScript . Ce n'est peut-être pas la lecture la plus excitante, mais cela ne servira à rien.

James Allardice
la source
8

Lorsque vous déclarez des variables globales, des fonctions, etc., elles, ehm, vont dans l'espace de noms global. Outre les problèmes de performances / mémoire (qui peuvent survenir), vous risquez de rencontrer des conflits de noms malheureux lorsque vous redéfinissez une variable importante ou n'utilisez pas la valeur que vous pensez utiliser.

Il faut éviter de définir des choses dans l'espace de noms global.

Sergio Tulentsev
la source
1
Un moyen d'éviter de définir des choses dans l'espace de noms global est d'utiliser des variables locales (déclarées avec "var" dans une fonction), mais alors la variable est ... locale à la fonction. Cela devrait être fait autant que possible.
Stéphane Glondu