【初心者向け】JavaScriptのグローバル変数とは?使い方と注意点
JavaScriptのグローバル変数を初心者向けに詳しく解説。基本的な概念から実際の使用例、よくある問題と回避方法まで、安全で効率的なコードを書くための重要な知識を分かりやすく紹介します。
【初心者向け】JavaScriptのグローバル変数とは?使い方と注意点
みなさん、JavaScriptを書いていて困ったことありませんか?
「この変数、他の関数からも使いたいな...」 「どこからでもアクセスできる変数って作れるの?」
こんな疑問を感じたことがある方、きっと多いですよね。
実は、JavaScriptにはグローバル変数という便利な仕組みがあるんです! これを使えば、プログラム全体で共有できる変数を作れるようになります。
この記事では、初心者の方でも分かりやすく、グローバル変数の基本から注意点まで詳しく解説します。 正しい使い方をマスターして、もっと便利なプログラムを作ってみませんか?
グローバル変数って何だろう?
簡単に言うとどんなもの?
グローバル変数とは、プログラム全体のどこからでも使える変数のことです。
普通の変数は関数の中でしか使えませんが、グローバル変数は違います。 どの関数からでも自由にアクセスできるんです。
// グローバル変数の例let globalMessage = "みんなで使える変数です";let globalCount = 0;
function showMessage() { // 関数内からグローバル変数を使える console.log(globalMessage); globalCount++; console.log(`カウント: ${globalCount}`);}
function resetCount() { // 別の関数からも使える globalCount = 0; console.log("カウントをリセットしました");}
showMessage(); // "みんなで使える変数です" "カウント: 1"showMessage(); // "みんなで使える変数です" "カウント: 2"resetCount(); // "カウントをリセットしました"
まるで、みんなが使える共通の道具箱みたいな感じですね。
グローバル変数の特徴
グローバル変数にはこんな特徴があります。
- どこからでもアクセスできる
- プログラムが終わるまでずっと存在する
- ブラウザのwindowオブジェクトに追加される(varの場合)
- 名前が重複すると問題が起きる可能性
// ブラウザでの例var browserGlobal = "ブラウザの変数";
console.log(window.browserGlobal); // "ブラウザの変数"console.log(browserGlobal); // "ブラウザの変数"
// letとconstはwindowに追加されないlet modernGlobal = "モダンな変数";console.log(window.modernGlobal); // undefinedconsole.log(modernGlobal); // "モダンな変数"
便利だけど、使い方に注意が必要なんです。
グローバル変数の作り方
基本的な作成方法
一番簡単な方法は、関数の外で変数を宣言することです。
// 方法1: var を使用var globalVar = "varで作った変数";
// 方法2: let を使用let globalLet = "letで作った変数";
// 方法3: const を使用const globalConst = "constで作った変数";
function testGlobalAccess() { console.log(globalVar); // アクセスできる console.log(globalLet); // アクセスできる console.log(globalConst); // アクセスできる // 変更のテスト globalVar = "変更されたvar"; globalLet = "変更されたlet"; // globalConst = "変更不可"; // エラー!constは変更できない}
testGlobalAccess();console.log(globalVar); // "変更されたvar"console.log(globalLet); // "変更されたlet"
どの方法でも作れますが、それぞれ特徴が違います。
危険な作り方(やらないで!)
宣言なしで変数を作ると、勝手にグローバル変数になってしまいます。
function createDangerousGlobal() { // 宣言なしで代入(危険!) dangerousGlobal = "危険な変数";}
createDangerousGlobal();console.log(dangerousGlobal); // "危険な変数"
// strict modeを使えば防げる"use strict";function strictFunction() { // strictGlobal = "エラーになる"; // ReferenceError}
このやり方は避けましょう。 思わぬバグの原因になります。
windowオブジェクトに直接追加
ブラウザでは、windowオブジェクトに直接追加することもできます。
// windowオブジェクトに追加window.customGlobal = "windowに追加した変数";console.log(customGlobal); // "windowに追加した変数"
// thisを使った方法this.anotherGlobal = "thisで追加";console.log(anotherGlobal); // "thisで追加"
でも、これもあまりおすすめしません。
実際に使ってみよう
アプリの設定を管理
アプリケーションの設定をグローバル変数で管理してみましょう。
// アプリの設定をグローバルで管理const APP_CONFIG = { version: "1.0.0", apiUrl: "https://api.example.com", theme: "light", language: "ja", debugMode: false};
// 設定を変更する関数function updateTheme(newTheme) { if (["light", "dark", "auto"].includes(newTheme)) { APP_CONFIG.theme = newTheme; console.log(`テーマを ${newTheme} に変更しました`); applyTheme(); } else { console.log("無効なテーマです"); }}
function applyTheme() { document.body.className = `theme-${APP_CONFIG.theme}`; console.log(`テーマ ${APP_CONFIG.theme} を適用しました`);}
// 使用例console.log(`アプリバージョン: ${APP_CONFIG.version}`);updateTheme("dark");
アプリの設定が一箇所で管理できて便利ですね。
ユーザー情報を保持
ログインしたユーザーの情報を保持してみましょう。
// ユーザー情報をグローバルで管理let currentUser = null;
function login(username, email) { currentUser = { username: username, email: email, loginTime: new Date(), isLoggedIn: true }; console.log(`${username} さんがログインしました`); updateUserInterface();}
function logout() { if (currentUser) { console.log(`${currentUser.username} さんがログアウトしました`); currentUser = null; updateUserInterface(); }}
function updateUserInterface() { if (currentUser && currentUser.isLoggedIn) { console.log(`ようこそ、${currentUser.username} さん`); // ここでUIの更新 } else { console.log("ログインしてください"); // ここでログインフォームの表示 }}
function getCurrentUser() { return currentUser;}
// 使用例login("太郎", "taro@example.com");console.log("現在のユーザー:", getCurrentUser());logout();
ユーザー情報が色んな場所から使えて便利です。
ショッピングカート
ネットショップのカート機能を作ってみましょう。
// ショッピングカートをグローバルで管理let shoppingCart = [];let cartTotal = 0;
function addToCart(productId, productName, price, quantity = 1) { // 既にある商品かチェック let existingItem = shoppingCart.find(item => item.id === productId); if (existingItem) { existingItem.quantity += quantity; console.log(`${productName} の数量を ${quantity} 個追加しました`); } else { let newItem = { id: productId, name: productName, price: price, quantity: quantity }; shoppingCart.push(newItem); console.log(`${productName} をカートに追加しました`); } updateCartTotal(); displayCart();}
function removeFromCart(productId) { let index = shoppingCart.findIndex(item => item.id === productId); if (index !== -1) { let removedItem = shoppingCart.splice(index, 1)[0]; console.log(`${removedItem.name} をカートから削除しました`); updateCartTotal(); displayCart(); }}
function updateCartTotal() { cartTotal = shoppingCart.reduce((total, item) => { return total + (item.price * item.quantity); }, 0);}
function displayCart() { console.log("=== ショッピングカート ==="); if (shoppingCart.length === 0) { console.log("カートは空です"); } else { shoppingCart.forEach(item => { console.log(`${item.name} × ${item.quantity} = ¥${item.price * item.quantity}`); }); console.log(`合計: ¥${cartTotal}`); } console.log("========================");}
// 使用例addToCart(1, "ノートPC", 89800, 1);addToCart(2, "マウス", 2980, 2);addToCart(1, "ノートPC", 89800, 1); // 既存商品の数量追加removeFromCart(2);
カート情報がどの関数からでも更新できて便利ですね。
ローカル変数との違いを知ろう
スコープの違い
グローバル変数とローカル変数の違いを見てみましょう。
// グローバル変数let globalVariable = "グローバルスコープ";
function demonstrateScope() { // ローカル変数 let localVariable = "ローカルスコープ"; console.log("関数内から:"); console.log("グローバル変数:", globalVariable); // 使える console.log("ローカル変数:", localVariable); // 使える}
demonstrateScope();
console.log("関数外から:");console.log("グローバル変数:", globalVariable); // 使える// console.log("ローカル変数:", localVariable); // エラー!使えない
ローカル変数は関数の外では使えないんです。
変数の隠蔽(シャドウイング)
同じ名前の変数があると、ローカル変数が優先されます。
let message = "グローバルメッセージ";
function testShadowing() { let message = "ローカルメッセージ"; // グローバル変数を隠す console.log("関数内のmessage:", message); // "ローカルメッセージ" // グローバル変数にアクセスするには console.log("グローバルのmessage:", window.message);}
testShadowing();console.log("関数外のmessage:", message); // "グローバルメッセージ"
名前が同じだと、混乱の原因になります。
よくある問題と解決方法
名前が重複する問題
// 問題のある例:名前衝突var name = "ユーザー名";var count = 0;
// 他のコードが同じ名前を使用var name = "別の名前"; // 元の値が上書きされるvar count = "文字列"; // 型も変わってしまう
console.log(name); // "別の名前"console.log(count); // "文字列"
これは危険ですね。 解決方法を見てみましょう。
// 解決方法1: 名前空間を使うconst MyApp = { name: "ユーザー名", count: 0, config: { version: "1.0.0", debug: false }};
console.log(MyApp.name); // "ユーザー名"console.log(MyApp.count); // 0
// 解決方法2: プリフィックスを付けるconst myapp_name = "ユーザー名";const myapp_count = 0;const myapp_config = { version: "1.0.0" };
これで安全に管理できます。
意図しない変更の問題
// 問題のある例:勝手に変更されるlet userSettings = { theme: "light", language: "ja"};
function someFunction() { // 意図せずグローバル変数を変更 userSettings.theme = "dark"; userSettings.newProperty = "追加されたプロパティ";}
console.log("変更前:", userSettings);someFunction();console.log("変更後:", userSettings); // 勝手に変更される
これも困りますね。 解決方法があります。
// 解決方法1: Object.freeze()で保護const protectedSettings = Object.freeze({ theme: "light", language: "ja"});
function saferFunction() { // protectedSettings.theme = "dark"; // エラーまたは無視される console.log("設定は保護されています");}
// 解決方法2: 関数に引数として渡すfunction processSettings(settings) { // コピーを作成 let localSettings = { ...settings }; localSettings.theme = "dark"; return localSettings;}
let originalSettings = { theme: "light", language: "ja" };let modifiedSettings = processSettings(originalSettings);console.log("元の設定:", originalSettings); // 変更されないconsole.log("変更された設定:", modifiedSettings); // 変更版
これで安全に使えますね。
安全な使い方をマスターしよう
名前空間パターン
関連する機能をオブジェクトにまとめる方法です。
// 良い例:名前空間パターンconst MyApplication = { // 設定 config: { version: "1.0.0", apiUrl: "https://api.example.com", debug: false }, // データ data: { users: [], currentUser: null }, // ユーティリティ関数 utils: { formatDate: function(date) { return date.toLocaleDateString("ja-JP"); }, generateId: function() { return Date.now().toString(36) + Math.random().toString(36).substr(2); } }, // 初期化 init: function() { console.log(`${this.config.version} を初期化中...`); this.loadUserData(); }, loadUserData: function() { console.log("ユーザーデータを読み込みました"); }};
// 使用例MyApplication.init();console.log("アプリバージョン:", MyApplication.config.version);
すべてが整理されて分かりやすいですね。
モジュールパターン
プライベートな変数と関数を作る方法です。
// モジュールパターンを使った実装const UserManager = (function() { // プライベート変数(外からアクセスできない) let users = []; let currentUserId = null; // プライベート関数 function validateUser(user) { return user && user.name && user.email; } function generateUserId() { return 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); } // パブリックAPI(外から使える関数) return { addUser: function(name, email) { if (!name || !email) { console.log("名前とメールアドレスは必須です"); return; } let user = { id: generateUserId(), name: name, email: email, createdAt: new Date() }; if (validateUser(user)) { users.push(user); console.log(`ユーザー ${name} を追加しました`); return user.id; } }, getUser: function(userId) { return users.find(user => user.id === userId); }, getAllUsers: function() { return users.map(user => ({ ...user })); // コピーを返す }, setCurrentUser: function(userId) { if (this.getUser(userId)) { currentUserId = userId; console.log(`現在のユーザーを ${userId} に設定しました`); } else { console.log("指定されたユーザーが見つかりません"); } }, getCurrentUser: function() { return currentUserId ? this.getUser(currentUserId) : null; }, getUserCount: function() { return users.length; } };})();
// 使用例let userId1 = UserManager.addUser("太郎", "taro@example.com");let userId2 = UserManager.addUser("花子", "hanako@example.com");
UserManager.setCurrentUser(userId1);console.log("現在のユーザー:", UserManager.getCurrentUser());console.log("総ユーザー数:", UserManager.getUserCount());
プライベートな部分が守られて安全ですね。
ES6モジュール(現代的な方法)
現代のJavaScriptでは、モジュールシステムを使うのがおすすめです。
// config.js ファイルexport const APP_CONFIG = { version: "1.0.0", apiUrl: "https://api.example.com", theme: "light"};
export function updateConfig(key, value) { if (APP_CONFIG.hasOwnProperty(key)) { APP_CONFIG[key] = value; console.log(`設定 ${key} を ${value} に更新しました`); }}
// userManager.js ファイルlet currentUser = null;
export function setCurrentUser(user) { currentUser = user;}
export function getCurrentUser() { return currentUser;}
export function clearCurrentUser() { currentUser = null;}
// main.js ファイルimport { APP_CONFIG, updateConfig } from './config.js';import { setCurrentUser, getCurrentUser } from './userManager.js';
console.log("アプリ設定:", APP_CONFIG);updateConfig('theme', 'dark');
setCurrentUser({ name: "太郎", email: "taro@example.com" });console.log("現在のユーザー:", getCurrentUser());
これが一番安全で現代的な方法です。
まとめ
JavaScriptのグローバル変数について学びました。
グローバル変数の特徴
- プログラム全体からアクセス可能
- プログラム終了まで存在
- 便利だけど注意が必要
実用的な使い方
- アプリケーション設定の管理
- ユーザー情報の保持
- ショッピングカートの管理
よくある問題
- 名前衝突のリスク
- 意図しない変更
- メモリの無駄遣い
安全な使い方
- 名前空間パターンを使う
- モジュールパターンを活用
- ES6モジュールがおすすめ
グローバル変数は便利な機能ですが、使い方に注意が必要です。 現代のJavaScript開発では、ES6モジュールを使うのがベストプラクティスです。
最初は簡単な例から始めて、だんだんと安全な方法を覚えていきましょう。 正しく使えるようになれば、とても便利なプログラムが作れるようになりますよ。
ぜひ今日から、これらの技術を活用して、もっと良いプログラムを作ってみませんか?