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

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

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

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

Q&A

解決済

2回答

5070閲覧

JavaScriptの変数宣言について var と let の使い分け

margutta

総合スコア34

JavaScript

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

4グッド

5クリップ

投稿2016/10/16 04:55

###前提・実現したいこと
JavaScriptの変数宣言について var と let の使い分けについて

質問 51551:JavaScriptでradioボタンで選択して背景色を変える(for loop を使って)
https://teratail.com/questions/51551
に関連して、変数の宣言の仕方 let について調べました。

参考資料:
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/let#内部関数でのクリーンなコード

var や let の他にも、const という宣言の方法もあることがわかりました。

今のところ、let はすごく便利だった!という印象と、↑のような説明が、なんとなくわかるような気がするといったところなのですが、以前にvar で書いたものの中には、let や const では動かないものもあります。便利なことを知った分怖くなったところもあり、どのように使い分けたらよいのかを理解することができたらよいなと思っています。

###発生している問題・エラーメッセージ

エラーメッセージ

###該当のソースコード

JavaScript

11.let でしか動かない 2 3<form id="myForm"> 4 <input type="radio" name ="color" value="green">green 5 <input type="radio" name ="color" value="red">red 6</form> 7 8<script> 9var c = document.getElementsByName('color'); 10for(let i=0; i<c.length; i++){ 11 c[i].onclick= function(){document.body.style.background = c[i].value; 12 } 13 } 14 </script> 15 162.var でしか動かない 17 18<p id="demo">default</p> 19 20<script> 21 var flws = ["Rose", "Tulip", "Pansy"]; 22 for (var i = 0, text = ""; i < flws.length; i++) { 23 text += flws[i] + "<br>"; 24 } 25 document.getElementById("demo").innerHTML = text; 26</script> 27

###試したこと
課題に対してアプローチしたことを記載してください

###補足情報(言語/FW/ツール等のバージョンなど)
関連質問:質問: JavaScriptでradioボタンで選択して背景色を変える(for loop を使って)
https://teratail.com/questions/51551

yosida001, ShoheiTai, nnahito, FLY2525👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

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

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

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

guest

回答2

0

ベストアンサー

varでしか動かないという2.のほうはtextをfor文内部のletで宣言しています。ですので、for文のあとにtextを使おうとする処理があるため、動かないのです。

varとletの使い分けはスコープだけ意識すればできると思います。まず、var宣言はすべて関数の最初に持ってきてください。varは関数の途中であっても関数の最初にあるものと見なされるため、動作は変わりません。**関数の途中でvarを書くと言う習慣をなくせば、varのスコープに悩むことは無くなります。**次に、変数宣言は一つだけにしてください。**varやletは複数の変数宣言をまとめてできますが、分離して考えられないため、混乱の元に過ぎません。**つまり、2.のコードは下記のようにします。

JavaScript

1var flws = ["Rose", "Tulip", "Pansy"]; 2var i = 0; 3var text = ""; 4for (; i < flws.length; i++) { 5 text += flws[i] + "<br>"; 6} 7document.getElementById("demo").innerHTML = text;

という形であれば、iはfor文の中だけで使っているので、letにしてfor文の中に押し込めますが、textはできないと言うことがわかると思います。

JavaScript

1var flws = ["Rose", "Tulip", "Pansy"]; 2var text = ""; 3for (let i = 0; i < flws.length; i++) { 4 text += flws[i] + "<br>"; 5} 6document.getElementById("demo").innerHTML = text;

【追記】

1.の方はあまり言及してませんでした。letはブロックスコープです。ですので、ブロック内部に押し留まります。ちょっと例を書いてみます。

JavaScript

1var list = []; 2for (let i = 0; i < 10; i++) { 3 let x = i * 2; 4 list.push(function() { 5 console.log(i, x); // それぞれのループで i と x は異なる。 6 }); 7} 8list[0](); // => 0 0 9list[1](); // => 1 2 10list[9](); // => 9 18

このコードのixをみてください。これらはlet宣言のため、for文のブロックの中でのみ有効です。for文のブロックは10回繰り返しますが、それぞれのブロックは独立しており、そのため、ixもそれぞれ10個作られます(ただしiは、次ループに行くときに以前のiの値を引き継ぎ、i++の処理をしてから別のiとして作られることになります)。listに入れられた無名関数の中のixもそれぞれが独立していることになります。

もし、これらがvar出会った場合は、関数(この場合は関数がありませんので、全体の先頭)にあるものとみなされます。

JavaScript

1var list = []; 2for (var i = 0; i < 10; i++) { 3 var x = i * 2; 4 list.push(function() { 5 console.log(i, x); // 全体で一つの i と x しかないため、同じものになる。 6 }); 7} 8list[0](); // => 10 18 9list[1](); // => 10 18 10list[9](); // => 10 18

そのため、ブロック内部のixはそれぞれたった1個を十回のループで共通して使うようになります。こうなるとlistに入れていく無名関数の中のixは全て同じものを指すことになってしまいます。これでは同じ事になりません。

では、どうやって考えれば良いのか。それは、変数をどのスコープ(範囲)で有効にしたいのかです。varを使った場合、関数全体がスコープになり、関数全体でたった一つしかありません。新たな関数の中でさらにvarで宣言しない限り、常に同じものを指します。対して、letであればブロックの内側だけです。**もし、そのブロックがfor文やwhile文などのループであれば、それぞれのループの中で独立して存在することになります。**そのようなループで独立して使うには、別途何らかの関数を用意しない限り、varでは実現できません。他にも、各ブロックで同じ変数を使ってしまった場合の影響を避けるために、letを使うという手法があります。

最後に、もし、letの場合をletを使わずに等価な形にした場合どうなるか、ですが、下記のようになります(変換にはBabelを使用)。

"use strict"; var list = []; var _loop = function _loop(i) { var x = i * 2; list.push(function () { console.log(i, x); // それぞれのループで i と x は異なる。 }); }; for (var i = 0; i < 10; i++) { _loop(i); } list[0](); // => 0 0 list[1](); // => 1 2 list[9](); // => 9 18

_loop関数のiとfor文のiは異なるiです。_loop関数は10回呼び出されるため、ixも10個作られると言うことがわかるかと思います。

投稿2016/10/16 05:08

編集2016/10/16 10:28
raccy

総合スコア21735

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

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

margutta

2016/10/16 09:17

解答を書いてくださりありがとうございます。 1. i (counta?) 以外の変数は、ループが始まる前に、とりあえず var で定義しておく. 2. for()の()内で、i の初期値を定義するときは、let で定義しておけば、再代入が必要になったときでも対応できる. まだ、どういう場合が、再代入なのかはわかっていないのですが、とりあえず、↑のように理解し、↓のように書いておけば、自分なりに納得できるのですが、問題ないでしょうか? ○ https://teratail.com/questions/51569 の場合 <script> var flws = ["Rose", "Tulip", "Pansy"]; var text=""; var len=flws.length; for (let i = 0 ; i < len; i++) { text += flws[i] + "<br>"; } document.getElementById("demo").innerHTML = text; </script> ○ https://teratail.com/questions/51551 の場合 <script> var c = document.getElementsByName('color'); len=c.length; for(let i=0; i<len; i++){ c[i].onclick= function(){document.body.style.background = c[i].value; } } </script> お忙しい中、回答を書いてくださり、ありがとうございました。自分一人では気付けないことを教えていただき感謝しています。
raccy

2016/10/16 10:30

1.について余り書いてませんでしたね。追記しました。 iだから…ではなく、iをどこで使いたいかです。関数全体で一つなのか、ブロックの中だけで各ループではそれぞれ別のもとして扱いたいのか。見える範囲を意識するとletはどう使うのかが意識できると思います。
margutta

2016/10/16 13:47

この説明を胸に自分の成長を待ちたいと思います。ありがとうございました!
guest

0

2.var でしか動かない

書くならこうとか。

JavaScript

1const flws = ["Rose", "Tulip", "Pansy"]; 2let text = ""; 3for (let i = 0; i < flws.length; i++) { 4 text += flws[i] + "<br>"; 5} 6document.getElementById("demo").innerHTML = text; 7```**動くサンプル:**[https://jsfiddle.net/90fgtrgq/](https://jsfiddle.net/90fgtrgq/) 8 9--- 10 11【JavaScriptにおけるvar/let/constの使い分け】 12[https://sbfl.net/blog/2016/07/14/javascript-var-let-const/](https://sbfl.net/blog/2016/07/14/javascript-var-let-const/) 13 14var, let, constの使い分けについて|もっこりJavaScript|ANALOGIC(アナロジック)】 15[http://analogic.jp/var-let-const/](http://analogic.jp/var-let-const/) 16

投稿2016/10/16 05:15

編集2016/10/16 05:25
kei344

総合スコア69398

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

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

margutta

2016/10/16 09:19

let を 教えていただき、大変ありがたかったです。教えていただいた資料もじっくり拝見したいと思います。ありがとうございました。
kei344

2016/10/16 09:27

「再代入」については、下記のようなことを指します。 var a = 0; a = 1; // 再代入 「const 」は再代入禁止なので出来ません。コードの中で再代入する必要が無い変数というものは結構多いので、それに使います。 const b = 0; b = 1; // エラー「TypeError: invalid assignment to const `b'」
margutta

2016/10/16 10:19

納得!! できた!! と思います。 あまたの本で、var が、幅を利かせている、ということのほかに、再代入をすごく難しく考えていてしまっていたので、 わかりませんでした。スッキリした感じがします。 1つだけ、なんとなく、もやっとしているのは、51551(https://teratail.com/questions/51551)で、 「onclick を実行する時点で変数 i が c.length(2?or c.length)になっている」とおっしゃっていらしたところ。 それが、var を let にかえると直ってしまうのはどうしてなんだろう....と、その辺のわけは、まだちょっとわからないままでいます。 ありがとうございました。
kei344

2016/10/16 11:09

raccyさんの追記に回答が追記されていますので、そちらを参考にしてみてください。「スコープ」が重要です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問