JavaScript | 基礎構文:変数・定数 – グローバル変数の扱い

JavaScript
スポンサーリンク

グローバル変数の扱い

グローバル変数は「プログラム全体から参照できる変数」です。便利に見えますが、扱いを誤るとバグの温床になります。安全な使い方と、避けるためのテクニックを初心者向けに整理します。


何がグローバル変数か

  • 定義: どの関数・ブロックにも属さず、全ファイルから参照できる変数。
  • ブラウザ: window(または globalThis)のプロパティとして存在。
  • Node.js: モジュールごとにスコープが分かれるが、globalThis は共通。
// ブラウザ
let count = 0;           // グローバル
console.log(window.count); // 0

// Nodeでも globalThis にアクセス可
console.log(globalThis === window); // ブラウザなら true
JavaScript

グローバル変数のメリット・デメリット

  • メリット:
    • 共有: どこからでも参照できるため、設定値などを共有しやすい。
  • デメリット:
    • 衝突: 同名変数が上書きされやすい。
    • 追跡困難: どこで変更されたか追いにくい。
    • テスト困難: 状態が残るため、再現性が下がる。
    • 隠れ依存: コードの依存関係が不透明になる。

例題:安易なグローバルで起こるバグ

// file A
let status = "idle";
function start() { status = "running"; }

// file B
function reset() { status = "idle"; } // 意図せず上書き
start();
reset();
console.log(status); // "idle"(Aの意図が壊れる)
JavaScript
  • 教訓: グローバルを共有すると、知らない場所の更新で挙動が壊れる。

暗黙的なグローバル(やってはいけない)

  • 現象: 宣言なしの代入で勝手にグローバル変数になる(非strictモード)。
  • 対策: かならず let / const で宣言する。"use strict" を使う。
// 悪い例(非strict)
x = 10;        // 宣言なし → 暗黙のグローバル
console.log(window.x); // 10

// 良い例(strict)
"use strict";
// x = 10; // エラー:宣言が必要
let x = 10;   // 明示的に宣言
JavaScript

安全な扱い方(ベストプラクティス)

  • 最小限にする:
    • ラベル: グローバルは「設定・定数・エントリポイント」など本当に必要なものだけ。
  • 名前空間オブジェクトにまとめる:
    • 衝突回避: ひとつのグローバルに集約し、その下にまとめる。
// 一つのグローバルに集約
const App = {
  config: { apiBase: "https://example.com", timeout: 5000 },
  state: { loggedIn: false },
  start() { console.log("start"); }
};
// 参照
console.log(App.config.timeout);
App.state.loggedIn = true;
JavaScript
  • 即時関数/ブロックスコープで囲う:
    • 漏れ防止: ファイル内の実装詳細を外へ出さない。
// ブロックで閉じる(ES6以降)
{
  const SECRET = "token";
  let cache = {};
  // 外から見えない
}
// console.log(SECRET); // エラー
JavaScript
  • モジュールを使う(推奨):
    • ES Modules: type="module" でスクリプトを読み込むと、ファイルはモジュールスコープになり、トップレベル変数はグローバルに出ない。
<script type="module">
  const local = 1;    // グローバルにならない
  export const answer = 42; // 必要なものだけ公開
</script>
JavaScript
  • 不変データは const + Freeze:
    • 改変防止: 設定値などは不変にする。
const CONFIG = Object.freeze({
  API: "https://example.com",
  TIMEOUT: 5000
});
// CONFIG.TIMEOUT = 1000; // 変更できない
JavaScript

グローバル値の読み書きを明確にする

  • 読み取り専用にする:
    • 関数で提供: 直接代入させず、関数越しに操作。
const App = (() => {
  let count = 0; // 外から直接触られない

  return {
    getCount() { return count; },
    increment() { count++; },
    reset() { count = 0; }
  };
})();

App.increment();
console.log(App.getCount()); // 1
// App.count = 99; // 無効(外から見えない)
JavaScript

使い分けの目安

  • グローバルにして良いもの:
    • 定数: バージョン、APIベースURL、UIテーマ名など。
    • エントリ関数: App.start() のような起動口。
  • グローバルにしないもの:
    • 可変状態: ログイン状態、カウンタ、キャッシュ。
    • 内部用のユーティリティ: そのファイルで完結すべき関数や変数。

ミニ練習

  • 問1: 暗黙のグローバルを防ぐように修正せよ。
// 悪い
message = "Hello";
// 良い
let message = "Hello";
JavaScript
  • 問2: 名前空間にまとめて衝突を避けるコードに書き換えよ。
// 悪い
let timeout = 3000;
function start() { /* ... */ }

// 良い
const App = {
  timeout: 3000,
  start() { /* ... */ }
};
JavaScript
  • 問3: 設定値を不変にして安全に参照せよ。
const CONFIG = Object.freeze({ retries: 3 });
function run() { console.log(CONFIG.retries); }
run();
JavaScript

まとめ

  • グローバルは便利だが危険: 衝突・追跡困難・テスト性低下の原因になる。
  • 暗黙的なグローバルは禁止: かならず let/const"use strict"
  • 最小限+名前空間+モジュール: グローバル汚染を避け、公開範囲をコントロールする。
  • 不変化と関数越し操作: 直接代入させず、API化して安全に扱う。

この基礎を守るだけで、コードの安定性と可読性がぐっと上がります。次は「ローカルスコープ」「ブロックスコープ」と組み合わせて、変数の見える範囲をさらに整理していきましょう。

タイトルとURLをコピーしました