JavaScriptの変数
変数はデータを格納する箱のようなものです。各箱に名前を付け、データを入れたり出したり、いつでも交換したりできます。
変数とは
名前の付いた箱の列を想像してください。「名前」という箱に「太郎」が入り、「年齢」という箱に25が入ります。中身は変わりますが、ラベルは同じまま — それが変数です。
JSでは、宣言キーワード(var / let / const)で変数を作成し、イコール記号で値を代入します:
HTML
<script>
var name = "太郎";
let age = 25;
const PI = 3.14;
</script>
varの問題点
varはES6以前の唯一の変数宣言方法でした。頭を悩ませる2つの動作があります:
- 関数スコープ —
ifやforブロック内で宣言されたvar変数は外側からもアクセスでき、直感に反します - ホイスティング —
var宣言はスコープの先頭に「持ち上げられ」ますが、代入はされません。宣言前に変数を使用してもエラーにならず(値はundefined)、微妙なバグにつながります
この2つの動作により、varはバグの温床となっています。モダンJSでは、varはletとconstに大きく取って代わられました。
let — ブロックスコープ、推奨されるデフォルト
letはES6(2015年)で導入され、varの2つの問題を修正しました:
- ブロックスコープ —
{}内でのみアクセス可能で、ブロックの外からはアクセスできない - ホイスティングなし — 宣言前に変数を使用するとエラーが発生する(テンポラルデッドゾーン)
日常開発では、再代入が必要な変数にはletを使いましょう。
const — 定数、再代入不可
constもブロックスコープを持ちますが、宣言時に代入が必要で、その後の再代入はできません。
注意:constが制限するのは「再代入」であり、「変更」ではありません。constがオブジェクトや配列を保持している場合、オブジェクトのプロパティや配列の要素は変更できます。変数を別のオブジェクトに向けることはできないだけです。
デフォルトはconstを使い、再代入が必要な場合にletに切り替える — これがベストプラクティスです。
変数の命名ルール
- 英字、アンダースコア
_、ドル記号$で始める必要がある - 以降の文字は英字、数字、アンダースコア、ドル記号が使用可能
- 数字で始めることはできない
- JSのキーワード(
var、let、functionなど)は使用できない - camelCaseが推奨:
firstName、totalPrice
複数の変数を宣言する
カンマで区切って複数の変数を一度に宣言できます:
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>
📖 まとめ
- 変数はデータを格納する箱で、宣言キーワード + 変数名 + 代入で作成する
varは関数スコープとホイスティングの問題がある — モダンJSでは避けるletはブロックスコープでホイスティングなし — 再代入が必要な場合に使用constはブロックスコープで再代入不可 — 宣言時に代入が必要constは再代入を防ぐが、オブジェクト/配列のプロパティや要素は変更可能- 優先順位: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を使いましょう。
📝 演習
- 基礎:
constであなたの名前を持つ定数SITE_NAMEを宣言し、letでvisitCountを0に設定して、両方の値をページに表示してください。 - 中級:ボタンを持つページを作成し、「訪問カウンター」をシミュレートしてください。クリックごとに
visitCountが1増加し、現在の値を表示します。letが再代入を許可し、constが許可しないことに注目してください。 - 上級:
constの学生オブジェクト{ name: "太郎", scores: [80, 90, 75] }を持つページを作成してください。その後、新しいスコア85を追加し、平均を計算し、名前を「花子」に変更してください — すべてconstを再代入せずに、オブジェクトの内容が変更可能であることを証明してください。



