【JavaScript】グローバルスコープ/モジュールスコープの違い

# **JavaScript におけるグローバルスコープとモジュールスコープの違い**

JavaScript では、関数や変数を **グローバルスコープ** で定義するか、**モジュールスコープ** に限定するかによって、挙動が大きく異なります。特に、ブラウザ環境で **HTML のインラインイベント (`onclick="executeFunction()"`) で関数を呼び出す場合、グローバルスコープが関係するため注意が必要** です。

---

## **1. `window.executeFunction = function() { ... };` (グローバルスコープ)**

```js
window.executeFunction = function() {
    console.log("関数が実行されました");
};
```

### **📌 グローバルスコープの特徴**
✅ **`window` はブラウザのグローバルオブジェクト** → `window` に代入すると、どこからでも `executeFunction()` を呼び出せる。  
✅ **HTML のインライン `onclick="executeFunction()"` でも呼び出し可能**。  
✅ **他のスクリプトやモジュールからもアクセス可能** だが、**名前の衝突リスク** がある。

✅ **HTML のインラインイベントが動作する例**
```html
<button onclick="executeFunction()">関数を実行</button>
```
➡️ **インライン `onclick` で `executeFunction()` を実行可能**（`window.executeFunction` として登録されているため）。

---

## **2. `var executeFunction = function() { ... };` (古い書き方)**

```js
var executeFunction = function() {
    console.log("関数が実行されました");
};
```

### **📌 `var` の特徴**
✅ **`var` で宣言した変数は関数スコープを持つ**  
✅ **ブラウザのグローバルスコープでは `window.executeFunction` に近い挙動をするが、ES Modules では異なる挙動をとる**  
✅ **`var` は再宣言が可能なため、意図しない変数の上書きが発生しやすい**  
✅ **ES6 以降は `var` は推奨されず、`const` や `let` が主流**  

❌ **`var` の問題点**
- グローバルスコープを汚染しやすい
- `let` や `const` のようにブロックスコープを持たない

✅ **推奨される書き方**
```js
let executeFunction = function() {
    console.log("関数が実行されました");
};
```

---

## **3. `const executeFunction = function() { ... };` (モジュール / ブロックスコープ)**

```js
const executeFunction = function() {
    console.log("関数が実行されました");
};
```

### **📌 モジュールスコープの特徴**
✅ **`const` や `let` で定義した変数はスコープ内でのみ有効**。
✅ **モジュール (`type="module"`) や `{}` の中で定義すると、グローバルには公開されない**。
✅ **HTML のインライン `onclick="executeFunction()"` ではエラーになる**（グローバルスコープに登録されないため）。

❌ **HTML のインラインイベントが動作しない例**
```html
<button onclick="executeFunction()">関数を実行</button>
```
➡️ `Uncaught ReferenceError: executeFunction is not defined` となる。

✅ **代わりに `addEventListener` を使うべき**
```js
document.getElementById("actionButton").addEventListener("click", executeFunction);
```

---

## **4. `type="module"` を指定した場合の違い**

JavaScript の `<script>` タグに `type="module"` を指定すると、**そのスクリプトはデフォルトでモジュールスコープとなり、グローバルオブジェクト (`window`) に変数や関数を登録しなくなる** という重要な違いがあります。

### **📌 `type="module"` の特徴**
✅ **モジュール内の変数や関数はグローバルスコープに登録されない**  
✅ **`import` / `export` を使用してスクリプトを分割できる**  
✅ **ブラウザ環境でも `strict mode` が自動適用される**  

❌ **HTML のインライン `onclick="executeFunction()"` は動作しない**

```html
<script type="module">
    const executeFunction = () => {
        console.log("関数が実行されました");
    };
</script>

<button onclick="executeFunction()">関数を実行</button>
```
➡️ **エラー** (`executeFunction is not defined`)

✅ **解決策: `window` に登録する**
```html
<script type="module">
    window.executeFunction = () => {
        console.log("関数が実行されました");
    };
</script>

<button onclick="executeFunction()">関数を実行</button>
```
➡️ **このように `window.executeFunction = ...` とすることで、グローバルに公開可能**。

✅ **または `addEventListener` を使用する**
```html
<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"` を活用**

---

**結論: 「グローバルに公開すべきか？」を考えて適切なスコープ設計を！** 🚀