JavaScript におけるグローバルスコープとモジュールスコープの違い
JavaScript では、関数や変数を グローバルスコープ で定義するか、モジュールスコープ に限定するかによって、挙動が大きく異なります。特に、ブラウザ環境で HTML のインラインイベント (onclick="executeFunction()"
) で関数を呼び出す場合、グローバルスコープが関係するため注意が必要 です。
1. window.executeFunction = function() { ... };
(グローバルスコープ)
window.executeFunction = function() {
console.log("関数が実行されました");
};
📌 グローバルスコープの特徴
✅ window
はブラウザのグローバルオブジェクト → window
に代入すると、どこからでも executeFunction()
を呼び出せる。
✅ HTML のインライン onclick="executeFunction()"
でも呼び出し可能。
✅ 他のスクリプトやモジュールからもアクセス可能 だが、名前の衝突リスク がある。
✅ HTML のインラインイベントが動作する例
<button onclick="executeFunction()">関数を実行</button>
➡️ インライン onclick
で executeFunction()
を実行可能(window.executeFunction
として登録されているため)。
2. var executeFunction = function() { ... };
(古い書き方)
var executeFunction = function() {
console.log("関数が実行されました");
};
📌 var
の特徴
✅ var
で宣言した変数は関数スコープを持つ
✅ ブラウザのグローバルスコープでは window.executeFunction
に近い挙動をするが、ES Modules では異なる挙動をとる
✅ var
は再宣言が可能なため、意図しない変数の上書きが発生しやすい
✅ ES6 以降は var
は推奨されず、const
や let
が主流
❌ var
の問題点
- グローバルスコープを汚染しやすい
-
let
やconst
のようにブロックスコープを持たない
✅ 推奨される書き方
let executeFunction = function() {
console.log("関数が実行されました");
};
3. const executeFunction = function() { ... };
(モジュール / ブロックスコープ)
const executeFunction = function() {
console.log("関数が実行されました");
};
📌 モジュールスコープの特徴
✅ const
や let
で定義した変数はスコープ内でのみ有効。
✅ モジュール (type="module"
) や {}
の中で定義すると、グローバルには公開されない。
✅ HTML のインライン onclick="executeFunction()"
ではエラーになる(グローバルスコープに登録されないため)。
❌ HTML のインラインイベントが動作しない例
<button onclick="executeFunction()">関数を実行</button>
➡️ Uncaught ReferenceError: executeFunction is not defined
となる。
✅ 代わりに addEventListener
を使うべき
document.getElementById("actionButton").addEventListener("click", executeFunction);
4. type="module"
を指定した場合の違い
JavaScript の <script>
タグに type="module"
を指定すると、そのスクリプトはデフォルトでモジュールスコープとなり、グローバルオブジェクト (window
) に変数や関数を登録しなくなる という重要な違いがあります。
📌 type="module"
の特徴
✅ モジュール内の変数や関数はグローバルスコープに登録されない
✅ import
/ export
を使用してスクリプトを分割できる
✅ ブラウザ環境でも strict mode
が自動適用される
❌ HTML のインライン onclick="executeFunction()"
は動作しない
<script type="module">
const executeFunction = () => {
console.log("関数が実行されました");
};
</script>
<button onclick="executeFunction()">関数を実行</button>
➡️ エラー (executeFunction is not defined
)
✅ 解決策: window
に登録する
<script type="module">
window.executeFunction = () => {
console.log("関数が実行されました");
};
</script>
<button onclick="executeFunction()">関数を実行</button>
➡️ このように window.executeFunction = ...
とすることで、グローバルに公開可能。
✅ または addEventListener
を使用する
<script type="module">
document.getElementById("actionButton").addEventListener("click", () => {
console.log("関数が実行されました");
});
</script>
<button id="actionButton">関数を実行</button>
➡️ グローバルを汚さず、スコープを適切に管理できる!
5. どの書き方を選ぶべきか?
書き方 | スコープ | インライン onclick で呼べる? |
推奨度 |
---|---|---|---|
window.executeFunction = ... |
グローバルスコープ | ✅ 呼べる | ⚠️ (小規模なら OK, 乱用注意) |
var executeFunction = ... |
関数スコープ | ✅ 呼べる | ❌ 非推奨 |
const executeFunction = ... や let executeFunction = ...
|
モジュール / ブロックスコープ | ❌ 呼べない | ✅ 推奨 |
type="module" を使用 |
モジュールスコープ | ❌ 呼べない | ✅ 推奨 (ES Modules 用) |
✅ 小規模 & 手軽にインラインイベントを使いたい → window.executeFunction
に登録
✅ 大規模 & 保守性重視 → addEventListener
を使い、スコープを適切に管理
✅ モジュール分割が必要なら type="module"
を活用
結論: 「グローバルに公開すべきか?」を考えて適切なスコープ設計を! 🚀