4 に答える
グローバルスコープへの「リーク」とは、ローカルスコープで使用されているものが意図せずにグローバルスコープで使用可能になった場合です。これは、現在のスコープでまだ定義されていない変数に割り当てることを意味します。
function myFunction() {
a=1;
}
myFunction();
alert(a);
//-> 1
予想とは異なる値/タイプの変数をもたらす名前の衝突が発生する可能性があるため、これは悪いことです。また、ステートメントvar
で使用される変数にキーワードを使用するのを忘れると、古いInternetExplorerでバグが発生する可能性があります。for
変数を意図的にグローバルにすることを「リーク」として分類することはしません。これは、変数をグローバルスコープに「注ぐ」ようなものだからです。window
ただし、オブジェクトの現在のプロパティ、または他のスクリプトやライブラリによって設定された変数との名前の衝突がまだ発生する可能性があるため、これは一部の人にとっては悪い習慣と見なされることがよくあります(少しメロドラマ的だと思いますが) 。
[[ショートストーリー]]
グローバル変数を作成せず、requirejsやcurlなどの非同期モジュールローダーを使用してください
[[長い話]]
そのコメントは不十分に構成されていました。
モジュールシステムに問題はありません。私はグローバル変数の使用についてまったく不満を言っていました。(私はまだ完全な汎用モジュールパターンが肥大化していると思います)。
すべてのグローバル変数を避けるべきかどうかは別の問題であり、スタイルの問題だと思います。非同期ローダーを使用してモジュールを渡すか、を使用window
してモジュールを渡すことができます。
- グローバルスコープへの「リーク」とはどういう意味ですか?
私が意味したのは、グローバル変数を作成することでした。グローバル変数の使用を最小限に抑えることはパターンです。関数型プログラミングでは、グローバル変数をゼロにすることは可能ですが、これはグローバルモジュールを使用する場合とは異なるパターンです。
- なぜそれが悪いのですか?
グローバルに状態があると、その状態が破損する可能性があります。
- どうやってそれを避けますか?
できません。ただし、グローバル変数の量を最小限に抑えることができます。グローバル状態を完全に回避するために、非同期ローダーを使用できます。これらは、使用できるいくつかのグローバル変数を定義します。
- 永続的なカスタムオブジェクトを作成したい場合、モジュールパターン(下記)が悪いのはなぜですか?
モジュールパターンに問題はありません。問題は、モジュールをグローバルに保存することです。問題は、グローバルな名前空間を持つことです。
- デザインパターンを使用すると、複雑なロジックをカプセル化できますが、JavaScriptで記述しているという理由だけで、カプセル化が突然悪くなるのでしょうか。
コメントの意図を明確にしたので、この質問は実際には関係ありません
- または...このコメンターは単に間違っていますか?
コメントの言い回しはせいぜい不十分でした。モジュールではなくグローバル名前付けに反対しましたが、これを適切に述べていませんでした。
別の方法は、非同期ローダーを使用してモジュールを定義することです。これらは、2つのグローバル変数に絞り込むことができます。define
およびrequire
。
require = function(moduleName, callback)
これにより、モジュールが取得され、返されます。
define = function(obj)
これはモジュールを定義します。
ここでの概念は、次のようにマルチファイルコードを作成することです。
// main.js
require([
"foo.js",
"bar.js",
...,
], function(foo, bar, ...) {
// do stuff
});
//foo.js
(function() {
var namespace = modulePatternCode;
...
define(namespace):
})();
//bar.js
(function() {
var namespace = modulePatternCode;
...
define(namespace):
})();
モジュールは名前空間ホルダーを「リーク」するだけなので、かなり受け入れられます。
RequireJSを使用したローダーの例:
utils.jsでユーティリティモジュールを定義します。
define(function () {
return {
each: function (iterable, callback) {
// ...
},
map: function (iterable, mapper) {
// ...
}
};
});
上記のモジュールを別のモジュール、たとえばmath.jsで使用します。
define([ "utils" ], function (utils) {
return {
sum: function (numbers) {
var sum = 0;
utils.each(numbers, function (n) {
sum += n;
});
return sum;
},
average: function (numbers) {
return this.sum(numbers) / numbers.length;
}
};
});
また、main.jsなどの別のファイルでmath.jsを使用できます。
console.log("About to add 1-3");
require([ "math" ], function (math) {
console.log(math.sum([ 1, 2, 3 ]));
});
あなたはまだ名前空間を持つことができ、それでもモジュール内でそれらを暖かく居心地の良いものに保つことができます:
namespace.js:
define([ "foo", "bar", "moo" ] function (foo, bar, moo) {
return {
foo: foo,
bar: bar,
moo: moo
};
});
次に、残りのモジュールは定義中にこの名前空間を使用できます。
define([ "namespace" ], function (namespace) {
namespace.foo(42);
});
または実行時に、他のモジュールで:
define(function () {
return {
initialize: function () {
require([ "namespace" ], function (namespace) {
namespace.foo(42);
});
}
};
});
上記の使用法では、define
とだけrequire
がグローバルです。もちろん、RequireJSでモジュールを定義/使用する方法にはさまざまな種類があるため、これらは単なる例示的な例です。