まず「グローバル変数」とは何か
グローバル変数は、
「プログラムの“どこからでも”読めて・書けてしまう変数」 のことです。
もう少し具体的に言うと、
どの関数の中にも入っていない場所
(ファイルの一番上とか)
で宣言された変数は、多くの場合「グローバル変数」になります。
let count = 0; // グローバル変数(どこからでも見える)
function increment() {
count = count + 1; // ここからも触れる
}
increment();
console.log(count); // 1
JavaScriptincrement 関数の中でも、外でも、count に自由にアクセスできています。
ここが重要です。
「どこからでも見える」=「どこからでも壊せる」
ということでもあるので、グローバル変数は強力で便利な反面、扱いを間違えるとすぐにカオスになります。
なぜグローバル変数が「危ない」と言われるのか
どこで書き換えられたか分かりにくくなる
例えば、こんなコードを考えます。
let status = "INIT"; // グローバル変数
function start() {
status = "RUNNING";
}
function stop() {
status = "STOPPED";
}
function debug() {
console.log("現在の状態:", status);
}
JavaScript小さな例ならまだしも、
実際のアプリではファイルが何十・何百と増えたりします。
その中のあちこちで status = ... と書かれていると、
「今の status は、どのタイミングで、どの関数によって変わったのか?」
を追いかけるのがだんだん難しくなっていきます。
デバッグ中にこんなことが起こります。
「さっきまで status が RUNNING だったのに、いつの間にか STOPPED になってる…」
「どこで変わったのかログを入れて調べまくる」
つまり、
グローバル変数は「触る人」が多すぎて、変更元の特定が難しくなりがち です。
名前の衝突(上書き事故)が起きやすい
グローバル変数は「みんなの共有スペース」に置いた変数です。
自分のファイルで let data = ... と書いていて、
どこか別のファイルでも let data = ... をグローバルに書いていると、
意図せず上書きし合う ことがあります。
小規模なコードならまだしも、
ライブラリや他人のコードも混ざってくると、
「あっちの data と、こっちの data が同じ名前だったせいでバグった」
みたいなことが本当に起きます。
テストや再利用が難しくなる
ある関数が「グローバル変数に依存している」と、
その関数単体をテスト・再利用しづらくなります。
let taxRate = 0.1;
function calcTotal(price) {
return price + price * taxRate;
}
JavaScript一見シンプルですが、この関数は taxRate というグローバル変数に依存しています。
他のプロジェクトで calcTotal だけ持っていこうとしても、taxRate もセットで持っていかなければ動きません。
ここが重要です。
グローバル変数に依存する関数は、「その関数だけを持ち出す」「設定を変える」といった再利用性・テスト性を犠牲にしがち。
とはいえ「グローバルに置きたいもの」もある
完全に悪ではない:全体設定・定数など
実務では、「アプリ全体で共有したい情報」も存在します。
例えば:
アプリ名
バージョン
API のベース URL
環境情報(開発・本番など)
こういったものは、
全体から参照できたほうが素直 なケースもあります。
const APP_NAME = "MyApp";
const API_BASE_URL = "https://api.example.com";
function showTitle() {
console.log(APP_NAME);
}
function fetchUser() {
return fetch(`${API_BASE_URL}/user`);
}
JavaScriptこのような 「変わらない定数」 については、
「グローバルに近い場所にまとめて定義する」のはむしろ自然な設計です。
「何でもかんでもグローバル」はダメ、「必要最小限だけグローバル」はアリ
重要なのは、
何でもかんでもグローバルに置くのではなく、
「アプリ全体の前提になる値」だけを厳選してグローバルにする
というバランス感覚です。
「1つの画面だけでしか使わない一時変数」までグローバルにする必要はありません。
そういうものは、できるだけ関数やブロックの中に閉じ込めるべきです。
ここが重要です。
**グローバル変数を「完全禁止」にするのではなく、
- 原則:使わない
- 例外:アプリ全体の設定/定数だけ、厳選して使う
という考え方が現実的な落としどころです。**
JavaScript における「グローバル」の具体的なイメージ
ブラウザなら window(グローバルオブジェクト)
ブラウザ環境では、
グローバル変数は裏側で window オブジェクトのプロパティになります。
var foo = 123;
console.log(window.foo); // 123
JavaScriptvar でグローバル宣言すると、window.foo としても見えてしまいます。
一方で、let / const でグローバルに書いた変数は、window のプロパティにはなりません(仕様の違い)。
let bar = 456;
console.log(window.bar); // undefined
console.log(bar); // 456
JavaScriptとはいえ、ブラウザでは
「どの関数にも入っていない let / const」も、
「そのファイル内の“トップレベルでどこからでも使える変数”」
という意味では、「グローバルに近い存在」です。
Node.js では少し事情が違う(が、初心者は「ファイルごとに閉じる」と覚えればOK)
Node.js では、各ファイルがモジュールとして扱われるため、
ファイルのトップレベルで宣言した let / const は、
そのファイル内でのみ有効 です。
これを「モジュールスコープ」と呼びます。
Node の世界では、「本当の意味でのグローバル」をむやみに使うことは推奨されません。
初心者のうちは、
「Node では、let / const はそのファイル専用の変数」
「他のファイルから使いたいものは、export / import を使う」
くらいの認識で十分です。
グローバル変数をどう「減らす」か:実践的な考え方
1: 本当に必要か、自分に問いかける
何か変数をトップレベルに置こうとしたとき、
一度こう自問してみてください。
「この値、どの関数からでもアクセスできる必要が本当にある?」
「特定の処理の中だけで完結しない?」
たとえば:
ユーザーの一時選択状態
一回の処理の途中でしか使わない計算結果
などは、その処理の中のローカル変数で十分です。
function process() {
let temp = calculate();
console.log(temp);
// temp はこの関数の中だけで十分
}
JavaScript2: 必要な値は「引数」と「戻り値」で渡せないか考える
グローバル変数に頼るのではなく、
「必要な値は引数で渡す」
という発想を徹底すると、
グローバル依存をかなり減らせます。
悪い例:
let taxRate = 0.1;
function calcTotal(price) {
return price + price * taxRate;
}
JavaScript良い例:
function calcTotal(price, taxRate) {
return price + price * taxRate;
}
const TAX_RATE = 0.1;
const total = calcTotal(1000, TAX_RATE);
JavaScriptcalcTotal は、
グローバル変数に依存せず、「もらった値だけ」で仕事をする関数 になりました。
そのぶん、テストしやすく、再利用もしやすくなります。
3: どうしても共有したい状態は「オブジェクトにまとめる」
アプリ全体でちょっとした状態を共有したいとき、
バラバラのグローバル変数を増やす代わりに、
一つのオブジェクトにまとめる のも良い方法です。
const appState = {
user: null,
isLoggedIn: false,
};
function login(user) {
appState.user = user;
appState.isLoggedIn = true;
}
function logout() {
appState.user = null;
appState.isLoggedIn = false;
}
JavaScriptappState 自体はグローバルな存在ですが、
「アプリの状態は基本ここに集約される」というルールにしておくと、
「どこで何が変わるのか」を追いやすくなります。
ここが重要です。
グローバル変数をゼロにするのが目的ではない。
「むやみにバラけさせない」「必要なものだけに限定する」「扱いを分かりやすくする」ことが大事。
初心者向けの「グローバル変数の扱い」まとめ
最後に、シンプルに整理します。
グローバル変数とは、「プログラムのどこからでも見える・書ける変数」のこと。
便利だが、
- どこで書き換えられたか分かりにくい
- 名前の衝突・上書き事故が起きやすい
- テストや再利用が難しくなる
といった問題を抱えやすい。
完全な悪者ではなく、
アプリ名・API のベース URL・定数など、「アプリ全体の前提となる情報」を置く場所としては有効。
ただし原則としては、
- まずローカル変数(関数の中・ブロックの中)で済ませられないか考える
- 値はできるだけ引数と戻り値で受け渡しする
- どうしても共有したい状態は、オブジェクトなどにまとめて「ここだけで管理する」と決める
ここが重要です。
「とりあえずグローバルに置く」ではなく、「本当にここに置くべきか?」と一度立ち止まる習慣を持つこと。
それだけで、将来の自分がデバッグで泣く回数が確実に減ります。
もしよければ、
グローバル変数を 1 つだけ使っている小さなサンプル(例えば let count = 0;)を書き、
それを「関数の引数+戻り値」で書き換える練習をしてみてください。
「この値、本当にグローバルじゃないとダメだった?」
と自分に問いかけて変形させてみることが、
グローバル変数との上手な距離感をつかむ近道になります。
