for文でのconstとletについていくつか質問があります。
Javascript
1const characters = [ 2 {name: "田中", age: 14}, 3 {name: "佐藤", age: 100}, 4 {name: "久保", age: 5}, 5 {name: "飯田", age: 19} 6 ]; 7 8for (let i = 0; i < characters.length; i++) { 9 10 const character = characters[i]; 11 console.log(`${character.name}`); 12 13}
上記のコードのループを疑似的に書くと以下のようになります。
JavaScript
1 //1回目のループ 2 { 3 const character = characters[i]; 4 console.log(`${character.name}`); 5 } 6 7 //2回目のループ 8 { 9 const character = characters[i]; 10 console.log(`${character.name}`); 11 } 12 13 //3回目のループ 14 { 15 const character = characters[i]; 16 console.log(`${character.name}`); 17 } 18
ここで質問があります。
インクリメントされる変数iはどこでインクリメントされるのでしょうか。
ループのたびに生成する別々のブロックの内部でインクリメントされるのでしょうか。
constがインクリメントできない理由は、ループのたびに生成する別々のブロックの外部でインクリメントするための変数iを定義するため,
ブロック内部で定義できるconst character = characters[i]; のように動かないのでしょうか。
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答5件
0
ECMAScriptの仕様を見る限り、for
文の実行のされ方はlet
の場合とconst
の場合で明確に場合分けされているので、そこを見ない限り理由はわからないと思われます。
Runtime Semantics - The for Statement - ECMAScript 2018 Specification
(let
かconst
を用いたfor
に該当するのは "for(LexicalDeclaration Expression; Expression) Statement" の部分で、isConst
を用いて場合分けされている)
Note: 以下は私なりの仕様の解釈ですが、間違っているかもしれません。
for (let ...)
は、イテレーションごとに別々のブロック(正確にはEnvironment)が生成され、各ブロックでループ変数が新しく作られ、一つ前のブロックでの最終的なループ変数の値がコピーされます。インクリメントは最初以外のイテレーションで、ループ変数が作られた直後に実行されます。
js
1for (let i = 0; i < characters.length; i++) { 2 const character = characters[i]; 3}
は以下のように実行されます。
js
1{ 2 let i = 0; 3} 4 5{ 6 let i = 一つ前のブロックの最終的なiの値; 7 // test 8 if (i < characters.length) ループから抜ける; 9 // body 10 { 11 const character = characters[i]; 12 } 13} 14 15{ 16 let i = 一つ前のブロックの最終的なiの値; 17 // increment 18 i++; 19 // test 20 if (i < characters.length) ループから抜ける; 21 // body 22 { 23 const character = characters[i]; 24 } 25} 26 27{ 28 let i = 一つ前のブロックの最終的なiの値; 29 // increment 30 i++; 31 // test 32 if (i < characters.length) ループから抜ける; 33 // body 34 { 35 const character = characters[i]; 36 } 37} 38// ...(以下繰り返し)...
一方for (const...)
の場合はループごとに新しいブロックは作られず、すべて同じブロックで実行されます。上の例だと以下のように実行されます。i
はconst
で宣言されているので当然最初のi++
で実行時エラーとなります。
{ const i = 0; /* ---------- */ // test if (i < characters.length) ループから抜ける; // body { const character = characters[i]; } // increment i++; /* ---------- */ // test if (i < characters.length) ループから抜ける; // body { const character = characters[i]; } // increment i++; /* ---------- */ // ...(以下繰り返し)... }
参考リソース
投稿2019/06/21 09:44
総合スコア2555
0
ベストアンサー
javascript
1let i = 0; 2if(i>=character.length) break; 3 //1回目のループ 4 { 5 const character = characters[i]; 6 console.log(`${character.name}`); 7 } 8i++; 9if(i>=character.length) break; 10 //2回目のループ 11 { 12 const character = characters[i]; 13 console.log(`${character.name}`); 14 } 15i++; 16if(i>=character.length) break; 17 //3回目のループ 18 { 19 const character = characters[i]; 20 console.log(`${character.name}`); 21 }
こうじゃないですかね
投稿2019/06/20 22:13
編集2019/06/21 04:35総合スコア12705
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/06/21 07:45
2019/06/21 10:05

0
質問終了済みに回答してすみません。
papinianusさんのご回答はわかりやすいのですが、実際のforループとスコープ周りの動作が異なりますのでご注意ください。karamarimoさんのご回答が参考になると思います。
js
1const characters = [ 2 {name: "田中", age: 14}, 3 {name: "佐藤", age: 100}, 4 {name: "久保", age: 5}, 5 {name: "飯田", age: 19} 6 ]; 7 8//質問のコード(一部追加) 9for (let i = 0; i < characters.length; i++) { 10 11 const character = characters[i]; 12 console.log(`${character.name}`); 13 setTimeout(function(){console.log(i)}, 1000); 14 15} 16/* 17田中 18佐藤 19久保 20飯田 210 221 232 243 25*/ 26 27 28//papinianusさんのコード(一部追加) 29loop:{ 30let i = 0; 31if(i>=characters.length) break loop; 32 //1回目のループ 33 { 34 const character = characters[i]; 35 console.log(`${character.name}`); 36 setTimeout(function(){console.log(i)}, 1000); 37 } 38i++; 39if(i>=characters.length) break loop; 40 //2回目のループ 41 { 42 const character = characters[i]; 43 console.log(`${character.name}`); 44 setTimeout(function(){console.log(i)}, 1000); 45 } 46i++; 47if(i>=characters.length) break loop; 48 //3回目のループ 49 { 50 const character = characters[i]; 51 console.log(`${character.name}`); 52 setTimeout(function(){console.log(i)}, 1000); 53 } 54} 55/* 56田中 57佐藤 58久保 592 602 612 62*/
投稿2019/06/22 01:21
編集2019/06/22 01:22総合スコア37413
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/06/24 05:13

0
while 文
for-of
-> for
-> while
の順に原始的でシンプルな繰り返し構文になっていくので、それらを上手く使って疑似コードを書いてみる事は有用だと思います。
原始的なコードは応用が利く分、発想の幅が広がります。
- for 文よりも原始的な while 文で再現
- for 文のブロックスコープは関数スコープで再現。関数
forLoop*
に引数i
(=j
,k
) が渡されると、複製された変数 i は関数スコープになるので、関数外からの干渉を受けません。 (Lhankor_Mhy さんが指摘されている性質)
JavaScript
1'use strict'; 2function handleTimeout (characters, k) { 3 const character = characters[k]; 4 console.log(`${character.name}`); 5} 6 7function forLoop1 (i) { 8 const character = characters[i]; 9 console.log(`${character.name}`); 10} 11 12function forLoop2 (j) { 13 setTimeout(function handleTimeout () { // 分かりやすさ重視で関数をネストさせていますが、毎回、関数を生成するのは無駄なので、基本的には関数を外に追い出す事を推奨します 14 const character = characters[j]; 15 console.log(`${character.name}`); 16 }, 100); 17} 18 19function forLoop3 (k) { // 関数 handleTimeout を外に追い出した場合 20 setTimeout(handleTimeout, 100, characters, k); 21} 22 23 24const characters = [ 25 {name: "田中", age: 14}, 26 {name: "佐藤", age: 100}, 27 {name: "久保", age: 5}, 28 {name: "飯田", age: 19} 29]; 30 31let i = 0; 32while (i < characters.length) { 33 forLoop1(i); // "田中" -> "佐藤" -> "久保" -> "飯田" 34 i++; 35} 36 37let j = 0; 38while (j < characters.length) { 39 forLoop2(j); // "田中" -> "佐藤" -> "久保" -> "飯田" 40 j++; 41} 42 43let k = 0; 44while (k < characters.length) { 45 forLoop3(k); // "田中" -> "佐藤" -> "久保" -> "飯田" 46 k++; 47}
※BabelのES5コンパイルも似たようなコードを生成していた記憶があります。
更新履歴
- 2019-06-22 11:54:16
setTimeout
のコールバック関数をネストしないforLoop3
を追記。ブロックスコープの説明を一文追記。
Re: Sano さん
投稿2019/06/22 02:30
編集2019/06/22 02:54総合スコア18194
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/06/22 02:35
2019/06/22 03:03

0
エムディエヌは加算のタイミングが文が実行された後といっていますょ
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Loops_and_iteration#for_statement
for ループが実行されるとき、次の処理が行われます :
- もしあれば、初期化式が実行されます。この式は通常、1 個またはそれ以上のループカウンタを初期化しますが、この構文ではいかなるレベルの複雑な式を入れることが可能です。初期化式で変数を宣言することもできます。
- 条件式 条件式が評価されます。条件式の値が true の場合、ループ文が実行されます。条件式の値が false の場合、for ループは終了します。条件式がすべて省略されている場合、条件式は真であると仮定されます。
3. 文が実行されます。複数の文を実行するには、それらの文をグループ化するためにブロック文 ({ ... }) を使用します。
4. もしあれば、更新式 加算式が実行されます。
5. ステップ 2 に制御が戻ります。
i++がi=i+1と同じだからiがconstになってぃると再代入エラァーになるんでゎないでしょぅか?
https://teratail.com/questions/96687
投稿2019/06/20 17:22
総合スコア70
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。