for 文での let とは何か
for 文での let は「ループの各反復ごとに“新しい束縛”を作る」宣言です。ここが重要です:i のようなインデックスを let で宣言すると、反復ごとに独立した値がクロージャ(非同期コールバック)にも正しく閉じ込められます。ES5 の var で起きがちだった「全部同じ値」問題を根本から解消します。
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), 0); // 1, 2, 3
}
JavaScriptvar との違い(最後の値を共有する事故を防ぐ)
var は“関数スコープ”、反復で束縛が共有される
var の i はループ全体で1つの変数を共有するため、非同期コールバックでは“最後の i”(終了後の値)になりがちです。
for (var j = 1; j <= 3; j++) {
setTimeout(() => console.log(j), 0); // 4, 4, 4(終了後の j を参照)
}
JavaScriptlet は“ブロックスコープ”、反復ごとに新しい束縛
let の i は各周回で独立するため、期待通りの値が保持されます。ここが重要です:非同期やイベントハンドラで安全に使えます。
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log(i), 0); // 1, 2, 3(周回ごとに別の i)
}
JavaScriptループヘッダでの let とスコープ(外側から見えない)
ループ変数はループブロックに限定される
for (let i = …) の i はループのブロックに閉じ、外から参照できません。スコープ汚染を防げます。
for (let i = 0; i < 2; i++) {}
// console.log(i); // ReferenceError(ループ外からは見えない)
JavaScriptループ内の“その都度の一時値”もブロックで守る
反復ごとの計算結果や定数はループ内で宣言し、外へ漏らさないと意図が明確になります。
let total = 0;
for (let i = 0; i < items.length; i++) {
const price = items[i].price ?? 0; // 反復専用の一時値
total += price;
}
JavaScriptTDZ(Temporal Dead Zone)と宣言順の注意
同名の再宣言は避ける、宣言は使う直前
ループ本体でヘッダと同名の let/const を再宣言するとエラーになります。ここが重要です:変数名は使い分け、宣言は使う直前に置く。
for (let i = 0; i < 3; i++) {
// const i = 99; // SyntaxError(同スコープで再宣言不可)
}
JavaScriptfor-of / for-in と let/const の使い分け
変更しない反復値は const、カウンタや累積は let
for-of/for-in では各反復ごとに新しい束縛が作られます。“その周回の値を変えない”なら const が最適です。集計など“変える値”は別変数を let で持ちます。
let sum = 0;
for (const n of [1, 2, 3]) {
sum += n; // sum は可変なので let
}
JavaScript非同期・イベントで効く具体例(重要ポイントの深掘り)
setTimeout や addEventListener と相性が良い
反復ごとに作るコールバックが“そのときの i”を持ち続けます。UIイベントを配列で束ねるときにも安全です。
const buttons = document.querySelectorAll("button");
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", () => {
console.log("clicked index:", i); // クリックしたボタンの i が正しく出る
});
}
JavaScript並列処理の発火順が変わっても安心
ネットワークやタイマーで完了順が前後しても、各タスクが“開始時の i”を保持しているため取り違えが起きません。
for (let i = 0; i < urls.length; i++) {
fetch(urls[i]).then(() => console.log("done:", i)); // どの順でも正しい i
}
JavaScript実務の指針(for での let をもっと安全に)
原則は const、必要なときだけ let(ループでも同じ)
反復値は const、カウンタや累積は let。ループ変数の寿命をループ内に閉じて、外へ漏らさない。
let total = 0;
for (let i = 0; i < rows.length; i++) {
const r = rows[i];
total += r.price ?? 0;
}
JavaScript破壊的操作は避け、非破壊で扱う
ループ中に配列を sort/splice などで壊すと、インデックスや走査が破綻します。結果だけ別配列に集める、toSorted や toSpliced を使うのが安全です。
const out = [];
for (let i = 0; i < rows.length; i++) {
const r = rows[i];
if (r.active) out.push({ id: r.id, price: r.price });
}
// out は新規、rows は保つ
JavaScript例題で理解を固める
var では失敗、let なら成功の対比
// 失敗例(var)
for (var j = 1; j <= 3; j++) {
setTimeout(() => console.log("var:", j), 0); // 4, 4, 4
}
// 成功例(let)
for (let i = 1; i <= 3; i++) {
setTimeout(() => console.log("let:", i), 0); // 1, 2, 3
}
JavaScriptfor-of と const の組み合わせ
let countActive = 0;
for (const u of users) { // 反復値 u は変えない
if (u.active) countActive++; // 累積は let
}
JavaScriptまとめ
for 文での let の核心は「反復ごとに新しい束縛を作り、非同期でも正しく値を保持する」ことです。var では共有束縛で最後の値が混入しがちですが、let はブロックスコープでそれを防ぎます。実務では“反復値は const、カウンタ・累積は let”、宣言は使う直前、配列は非破壊で扱う。これを徹底すれば、初心者でもループと非同期の組み合わせで安全に意図どおりのコードを書けます。
