404 Not Found

404 Not Found


nginx

JavaScriptの変数

変数はデータを格納する箱のようなものです。各箱に名前を付け、データを入れたり出したり、いつでも交換したりできます。

変数とは

名前の付いた箱の列を想像してください。「名前」という箱に「太郎」が入り、「年齢」という箱に25が入ります。中身は変わりますが、ラベルは同じまま — それが変数です。

JSでは、宣言キーワード(var / let / const)で変数を作成し、イコール記号で値を代入します:

HTML
<script>
var name = "太郎";
let age = 25;
const PI = 3.14;
</script>

varの問題点

varはES6以前の唯一の変数宣言方法でした。頭を悩ませる2つの動作があります:

  1. 関数スコープifforブロック内で宣言されたvar変数は外側からもアクセスでき、直感に反します
  2. ホイスティングvar宣言はスコープの先頭に「持ち上げられ」ますが、代入はされません。宣言前に変数を使用してもエラーにならず(値はundefined)、微妙なバグにつながります

この2つの動作により、varはバグの温床となっています。モダンJSでは、varletconstに大きく取って代わられました。

let — ブロックスコープ、推奨されるデフォルト

letはES6(2015年)で導入され、varの2つの問題を修正しました:

日常開発では、再代入が必要な変数にはletを使いましょう

const — 定数、再代入不可

constもブロックスコープを持ちますが、宣言時に代入が必要で、その後の再代入はできません。

注意:constが制限するのは「再代入」であり、「変更」ではありません。constがオブジェクトや配列を保持している場合、オブジェクトのプロパティや配列の要素は変更できます。変数を別のオブジェクトに向けることはできないだけです。

デフォルトはconstを使い、再代入が必要な場合にletに切り替える — これがベストプラクティスです。

変数の命名ルール

複数の変数を宣言する

カンマで区切って複数の変数を一度に宣言できます:

HTML
<script>
let a = 1, b = 2, c = 3;
</script>

ただし、可読性のため、1行に1つの変数を宣言することが推奨されます。

実例:varのホイスティングと関数スコープ

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JS変数 - varの問題</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 550px; margin: 60px auto; }
    .warn { background: #fff3e0; padding: 12px; border-radius: 8px; color: #E65100; border-left: 4px solid #FF9800; margin: 12px 0; }
    .result { background: #f5f5f5; padding: 16px; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; margin: 12px 0; }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #FF9800; margin: 6px; }
    button:hover { background: #F57C00; }
  </style>
</head>
<body>
  <h2>varの問題デモ</h2>
  <p class="warn">⚠️ varにはホイスティングと関数スコープの問題があります — モダンコードでは避けましょう</p>
  <button id="hoistBtn">デモ:ホイスティング</button>
  <button id="scopeBtn">デモ:スコープリーク</button>
  <div class="result" id="output">ボタンをクリックして結果を確認</div>
  <script>
    document.getElementById("hoistBtn").onclick = function() {
      var output = "";
      output += "var宣言前にxにアクセス: x = " + typeof x + "\n";
      var x = 10;
      output += "宣言後: x = " + x + "\n\n";
      output += "👆 ホイスティングにより宣言前でもエラーにならないが、値はundefined\n";
      output += "大規模プロジェクトでは簡単にバグの原因になります!";
      document.getElementById("output").textContent = output;
    };
    document.getElementById("scopeBtn").onclick = function() {
      var output = "";
      for (var i = 0; i < 3; i++) {
        // var iがループの外に漏れ出す
      }
      output += "ループ後、i = " + i + "\n\n";
      output += "👆 var iがループの外に漏れ出しました!\n";
      output += "let iを使えば、外からはアクセスできません";
      document.getElementById("output").textContent = output;
    };
  </script>
</body>
</html>

実例:letのブロックスコープ

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JS変数 - letのブロックスコープ</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 550px; margin: 60px auto; }
    .good { background: #e8f5e9; padding: 12px; border-radius: 8px; color: #2E7D32; border-left: 4px solid #4CAF50; margin: 12px 0; }
    .result { background: #f5f5f5; padding: 16px; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; margin: 12px 0; }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #4CAF50; margin: 6px; }
    button:hover { background: #388E3C; }
  </style>
</head>
<body>
  <h2>letのブロックスコープデモ</h2>
  <p class="good">✅ letはブロックスコープを持つ — {}の外からはアクセスできず、より安全です</p>
  <button id="letScopeBtn">デモ:letのブロックスコープ</button>
  <button id="letLoopBtn">デモ:ループ内のlet</button>
  <div class="result" id="output">ボタンをクリックして結果を確認</div>
  <script>
    document.getElementById("letScopeBtn").onclick = function() {
      let output = "ブロックスコープテスト:\n";
      let x = 100;
      output += "外側のx = " + x + "\n";
      {
        let x = 200;
        output += "内側のx = " + x + "\n";
      }
      output += "ブロック後、x = " + x + "\n\n";
      output += "👆 内側と外側のxは互いに独立しています";
      document.getElementById("output").textContent = output;
    };
    document.getElementById("letLoopBtn").onclick = function() {
      let output = "ループ内のlet:\n";
      for (let i = 0; i < 3; i++) {
        output += "ループ内、i = " + i + "\n";
      }
      output += "\n";
      try {
        output += "ループ外、i = " + i;
      } catch(e) {
        output += "ループ外のiにアクセス → エラー: " + e.message;
      }
      output += "\n\n👆 let iはループ内に制限され、外に漏れ出しません";
      document.getElementById("output").textContent = output;
    };
  </script>
</body>
</html>

実例:const定数

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JS変数 - const定数</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 550px; margin: 60px auto; }
    .tip { background: #e3f2fd; padding: 12px; border-radius: 8px; color: #1565C0; border-left: 4px solid #2196F3; margin: 12px 0; }
    .result { background: #f5f5f5; padding: 16px; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; margin: 12px 0; }
    button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; margin: 6px; }
    #constBtn { background: #9C27B0; }
    #objectBtn { background: #2196F3; }
  </style>
</head>
<body>
  <h2>const定数デモ</h2>
  <p class="tip">💡 constは再代入できませんが、オブジェクト/配列のプロパティや要素は変更できます</p>
  <button id="constBtn">デモ:constの再代入エラー</button>
  <button id="objectBtn">デモ:constオブジェクトの変更</button>
  <div class="result" id="output">ボタンをクリックして結果を確認</div>
  <script>
    document.getElementById("constBtn").onclick = function() {
      const PI = 3.14159;
      let output = "const PI = " + PI + "\n\n";
      output += "PI = 3.14への再代入を試みる:\n";
      try {
        PI = 3.14;
      } catch(e) {
        output += "❌ エラー: " + e.message;
      }
      output += "\n\n👆 一度代入されたconst変数は変更できません";
      document.getElementById("output").textContent = output;
    };
    document.getElementById("objectBtn").onclick = function() {
      const person = { name: "太郎", age: 25 };
      let output = "const person = " + JSON.stringify(person) + "\n\n";
      output += "person.age = 26に変更:\n";
      person.age = 26;
      output += "person = " + JSON.stringify(person) + "\n\n";
      output += "person.city = '東京'を追加:\n";
      person.city = "東京";
      output += "person = " + JSON.stringify(person) + "\n\n";
      output += "👆 constは変数の参照をロックし、オブジェクトの内容はロックしない\n";
      output += "ラベルがロックされた箱のようなもの — 中身はまだ変えられます";
      document.getElementById("output").textContent = output;
    };
  </script>
</body>
</html>

実例:var / let / const 比較

HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>JS変数 - 3つの宣言方法の比較</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 600px; margin: 60px auto; }
    table { width: 100%; border-collapse: collapse; margin: 16px 0; }
    th, td { padding: 10px; text-align: center; border: 1px solid #ddd; }
    th { background: #2196F3; color: #fff; }
    .bad { color: #f44336; }
    .good { color: #4CAF50; font-weight: bold; }
    button { margin-top: 12px; padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #e91e63; }
    #result { margin-top: 12px; padding: 16px; background: #f5f5f5; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; }
  </style>
</head>
<body>
  <h2>var / let / const 比較</h2>
  <table>
    <tr><th>機能</th><th>var</th><th>let</th><th>const</th></tr>
    <tr><td>スコープ</td><td class="bad">関数</td><td class="good">ブロック</td><td class="good">ブロック</td></tr>
    <tr><td>ホイスティング</td><td class="bad">あり(undefined)</td><td class="good">なし(TDZ)</td><td class="good">なし(TDZ)</td></tr>
    <tr><td>再代入可能</td><td class="bad">可</td><td>可</td><td class="bad">不可</td></tr>
    <tr><td>宣言前の使用</td><td class="bad">エラーなし</td><td class="good">エラー</td><td class="good">エラー</td></tr>
    <tr><td>推奨度</td><td class="bad">避ける</td><td class="good">推奨</td><td class="good">最優先</td></tr>
  </table>
  <button id="testBtn">比較テストを実行</button>
  <div id="result"></div>
  <script>
    document.getElementById("testBtn").onclick = function() {
      var output = "=== 比較テスト ===\n\n";
      output += "[var] 関数スコープ:\n";
      for (var i = 0; i < 3; i++) {}
      output += "var i(ループ外)= " + i + " (漏れ出している)\n\n";
      output += "[let] ブロックスコープ:\n";
      for (let j = 0; j < 3; j++) {}
      try {
        output += "let j(ループ外)= " + j;
      } catch(e) {
        output += "ループ外のlet jにアクセス → " + e.message + " (正しい動作)";
      }
      output += "\n\n[const] 再代入不可:\n";
      const MAX = 100;
      output += "const MAX = " + MAX + "\n";
      try {
        MAX = 200;
      } catch(e) {
        output += "再代入 → " + e.message + " (正しい動作)";
      }
      output += "\n\n結論: const > let >> var";
      document.getElementById("result").textContent = output;
    };
  </script>
</body>
</html>

📖 まとめ

  1. 変数はデータを格納する箱で、宣言キーワード + 変数名 + 代入で作成する
  2. varは関数スコープとホイスティングの問題がある — モダンJSでは避ける
  3. letはブロックスコープでホイスティングなし — 再代入が必要な場合に使用
  4. constはブロックスコープで再代入不可 — 宣言時に代入が必要
  5. constは再代入を防ぐが、オブジェクト/配列のプロパティや要素は変更可能
  6. 優先順位:constが最優先、letが次点、varは避ける

❓ よくある質問

Q constオブジェクトが変更できるなら、constの意味は何ですか?
A constは変数の参照が変わらないことを保証します。personを別のオブジェクトに誤って再代入することはできませんが、既存のオブジェクトプロパティの変更は問題ありません。箱のラベルをロックするようなもの(この箱は常に「太郎の箱」)ですが、中身は自由に入れ替えられます。
Q letとconst、いつどちらを使うべきですか?
A シンプルなルール:「この値は変わりますか?」と自問してください。変わらないならconst、変わるならletを使います。例えば、カウンターはlet、設定定数はconstを使います。実際には、letよりもconstをはるかに多く使うことになります。
Q varを今後も使えますか?
A 技術的には使えますが、使う理由はありません。letとconstはvarの完全なアップグレードで、varが必須でlet/constが動作しない場面はありません。レガシーコードでのvarの理解は問題ありませんが、新しいコードでは常にlet/constを使いましょう。

📝 演習

  1. 基礎constであなたの名前を持つ定数SITE_NAMEを宣言し、letvisitCountを0に設定して、両方の値をページに表示してください。
  2. 中級:ボタンを持つページを作成し、「訪問カウンター」をシミュレートしてください。クリックごとにvisitCountが1増加し、現在の値を表示します。letが再代入を許可し、constが許可しないことに注目してください。
  3. 上級constの学生オブジェクト{ name: "太郎", scores: [80, 90, 75] }を持つページを作成してください。その後、新しいスコア85を追加し、平均を計算し、名前を「花子」に変更してください — すべてconstを再代入せずに、オブジェクトの内容が変更可能であることを証明してください。
100%