質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

5回答

1818閲覧

constがインクリメントできない理由

Sano

総合スコア19

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

5クリップ

投稿2019/06/20 15:13

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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ECMAScriptの仕様を見る限り、for文の実行のされ方はletの場合とconstの場合で明確に場合分けされているので、そこを見ない限り理由はわからないと思われます。

Runtime Semantics - The for Statement - ECMAScript 2018 Specification
(letconstを用いた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...)の場合はループごとに新しいブロックは作られず、すべて同じブロックで実行されます。上の例だと以下のように実行されます。iconstで宣言されているので当然最初の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

karamarimo

総合スコア2551

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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
papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

miyabi_takatsuk

2019/06/21 01:21

if文で表現されると、すっごい動きわかりやすいですね・・・。 そして、構文の最後の"ド"を消し忘れてらっしゃいますよ 笑
papinianus

2019/06/21 04:35

ド… ありがとうございます
Lhankor_Mhy

2019/06/21 10:05

この擬似コードだと、それぞれのループでは変数iがブロックスコープを持たないことになるので、誤解が起きそうですね。
guest

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
Lhankor_Mhy

総合スコア36115

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

x_x

2019/06/24 05:13

正確を期せばループから抜けるのは break のときのみなので、最後にもこれが必要な気がします。 i++; if(i>=characters.length) break loop;
Lhankor_Mhy

2019/06/24 05:30

おっしゃるとおりです。 break以外にループを抜けない、という意味でもっと正確に書くなら、 i++; if(i>=characters.length) break loop; continue loop; かもしれません。 そして、そこまでやるなら解説用としてもwhile文で書いた方がわかりやすいので、think49さんのご回答に行き着くかもしれません。 解説用コードですから、誤解さえなければいいかな、ぐらいの感じで。
guest

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
think49

総合スコア18164

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lhankor_Mhy

2019/06/22 02:35

初見で「これも変数 i のスコープが違う」と思ったのですが、ブロックスコープをクロージャで再現している、と理解しました。よろしいですよね?
think49

2019/06/22 02:59

回答に追記しました。 To: Lhankor_Mhy さん 関数 forLoop2 に引数 j が渡された場合、変数 j は「関数 forLoop2 内にあるローカル変数 j」として再定義(複製)されます。 関数 forLoop2 が呼び出された時点で変数 j は外部からの干渉を受け付けなくなっているので、そこから先のクロージャは無関係だと思います。 forLoop3 のパターンでも変数 k は外部からの影響を受けません。
think49

2019/06/22 03:02

変数 characters に関してはスコープチェーン(回答のコードを「関数コード」と見るなら、クロージャ)で再現しています。
Lhankor_Mhy

2019/06/22 03:03

ああ、失礼。 おっしゃるとおり、クロージャ、は違いましたね。
guest

0

エムディエヌは加算のタイミングが文が実行された後といっていますょ

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Loops_and_iteration#for_statement

for ループが実行されるとき、次の処理が行われます :

  1. もしあれば、初期化式が実行されます。この式は通常、1 個またはそれ以上のループカウンタを初期化しますが、この構文ではいかなるレベルの複雑な式を入れることが可能です。初期化式で変数を宣言することもできます。
  2. 条件式 条件式が評価されます。条件式の値が true の場合、ループ文が実行されます。条件式の値が false の場合、for ループは終了します。条件式がすべて省略されている場合、条件式は真であると仮定されます。
    3. 文が実行されます。複数の文を実行するには、それらの文をグループ化するためにブロック文 ({ ... }) を使用します。
    4. もしあれば、更新式 加算式が実行されます。
    5. ステップ 2 に制御が戻ります。

i++がi=i+1と同じだからiがconstになってぃると再代入エラァーになるんでゎないでしょぅか?
https://teratail.com/questions/96687

投稿2019/06/20 17:22

mankoman

総合スコア70

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問