グローバル名前空間が汚染されるとはどういう意味ですか?


92

グローバル名前空間が汚染されるとはどういう意味ですか?

汚染されるグローバル名前空間の意味がよくわかりません。


1
将来の参照のためのリンク:JavaScript名前空間宣言
blong

回答:


124

ガベージコレクションに関するクイックノート

変数がスコープを失うと、ガベージコレクションの対象になります。それらがグローバルにスコープ指定されている場合、グローバル名前空間がスコープを失うまで、それらは収集に適格ではありません。

次に例を示します。

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

これをグローバル名前空間に追加すると(少なくとも私にとって)、10,000 kbのメモリ使用量(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個のグローバル変数が作成され、上書きされるか、誤って解釈される可能性があります。

機知に富む

グローバルな名前空間を汚染しないより機知に富んだアプローチは、これをすべてモジュールパターンでラップし、複数の変数を公開するときに1つのグローバル変数のみを使用することです。

次に例を示します(これは単純であり、エラー処理がないことに注意してください)。

//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

その良い説明をありがとう。簡単な質問:そのスニペットのエラー処理について何が見たいですか?
センテンザ2014

@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」で宣言)を使用することですが、変数は関数に対してローカルです。これは可能な限り行う必要があります。
ステファンGlondu
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.