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

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

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

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

Q&A

解決済

5回答

610閲覧

配列の文字列をclassとして挿入しようとするとundefinedになってしまう。

don-bongo

総合スコア3

JavaScript

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

0グッド

0クリップ

投稿2020/09/09 01:29

前提・実現したいこと

javascriptでクリックした要素に対して内容の変更とclassの付与を行いたいのですが、
配列に格納した文字列をループで指定した番号を渡して指定した上で、classを付与しようとするとundefinedになってしまいます。

発生している問題

classList.add(cls[i])の処理がundefinedを挿入してしまう。

該当のソースコード

javascript

1<body> 2 <div id="app"> 3 <div class="box"> 4 <div class="btn">あいうえお</div> 5 <div class="btn">かきくけこ</div> 6 <div class="btn">さしすせそ</div> 7 </div> 8 </div> 9 10 <script> 11 12 document.addEventListener('DOMContentLoaded',function(){ 13 var btns = document.querySelectorAll('.btn'); 14 let cls = ["btn01","btn02","btn03"] 15 for(var i = 0; i < btns.length; i++){ 16 btns[i].addEventListener('click',function(){ 17 this.innerHTML="変わったよ"; 18 this.classList.add(cls[i]) 19 },false); 20 } 21 },false); 22 </script> 23</body>

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

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

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

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

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

guest

回答5

0

私も以前同じことをしてしまいましたが、

btns[i].addEventListener('click',function(){ this.innerHTML="変わったよ"; this.classList.add(cls[i]) },false);

の中で i を使ってしまっているためですね。
具体的には this.classList.add(cls[i]) の部分です。

普通に考えると、それぞれのボタンが押された時に上記のiには0~2が順に入っているように見えますが違います。
btns[i].addEventListener('click',function(){
},false);

の中のプログラムはクリックイベントが発生したタイミングで実行され、そのタイミングのiの中身が適用されます。

つまり、このプログラムが一度実行されるとfor文が回り、iが足されていってiが3になった時点でループを抜け、
その後にクリックイベントが発生した際には
this.classList.add(cls[3])
のように処理されるということです。

投稿2020/09/09 01:44

mkk

総合スコア378

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

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

0

iを参照しているのは「クリックした後」です。
forが抜けた後の「3」がiの値です。
3はclsに持ってないindexなのでundefinedになります。
なので、イベントが発生したクラスが何番目なのかを取得するように組み直した方が良いです。

投稿2020/09/09 01:39

m.ts10806

総合スコア80765

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

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

don-bongo

2020/09/09 02:45

ご指摘の通り何番目のクラスかを取得して付与したら思い通りの動きができました。 どうもありがとうございます。
m.ts10806

2020/09/09 02:55

どう実装するのが望ましいかは要件次第です。
guest

0

こんにちは。

iはブロックスコープではないので、ループごとに値を保持することができず、ループが終わった後にインクリメントされるので、配列の範囲を超えてしまうので、undefinedになります。

参考:
よくある間違い: ループ内でクロージャを作成する | クロージャ - JavaScript | MDN

投稿2020/09/09 01:37

Lhankor_Mhy

総合スコア35860

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

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

0

ベストアンサー

こんにちは

最小限の修正で済ませるならば、ループカウンタの ivar ではなく let で宣言、初期化すると、意図通りになります。

diff

1- for(var i = 0; i < btns.length; i++){ 2+ for(let i = 0; i < btns.length; i++){

投稿2020/09/09 02:34

jun68ykt

総合スコア9058

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

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

don-bongo

2020/09/09 02:52

どうもありがとうございます。 やり方を変更せずに想定して通りの動きになりました。 重ねての質問で大変申し訳ありません。この場合letにすることでどのようなことが起きているのでしょうか。letとvarの違いを読み込んでも理解ができませんでした。。
jun68ykt

2020/09/09 03:36

大雑把にいうと、let を使うとループの毎回ごとに新しく変数 i が作られて、前回の値より1多い値で初期化されるので意図通りなりますが、var だと、このようにならず、同じひとつの変数 i を、addEventListener で設定している3つのコールバックで共有するため、どのbtnをクリックしたときも i の最後の値の3が使われて、cls[3] は undefined ということになってしまいます。 より詳しくは、下記 https://teratail.com/questions/62502 https://teratail.com/questions/205789 などですでに質問として投稿されているので、そちらを参照されるとよいでしょう。
jun68ykt

2020/09/09 03:51

補足です。 もし、let にせずに var のままでforループでやろうとすると、ループの各回での i の値を別の変数に保存しておいて、各コールバックが呼ばれたときに、var iの最後の値ではなく、各回で保存しておいた i の値がclsのインデクスとして使われるようにする必要があります。そのための解決策のひとつは、以下のようにクロージャーを使うことです。 https://codepen.io/jun68ykt/pen/ExKQOQa?editors=0010 上記の場合、毎回の i の値は、各回それぞれの変数 x に保存されています。
don-bongo

2020/09/09 09:34

ありがとうございます。 参考ページにて把握することができました。 この度は本当にありがとうございました。
jun68ykt

2020/09/09 09:48

どういたしまして。 疑問が解消されたようで、よかったです????
guest

0

javascript

1const cls = ["btn01","btn02","btn03"]; 2document.querySelectorAll('.btn').forEach((x,y)=>{ 3 x.addEventListener('click',()=>{ 4 x.textContent="変わったよ"; 5 x.classList.add(cls[y]); 6 }); 7});

投稿2020/09/09 02:34

編集2020/09/09 02:36
yambejp

総合スコア114572

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問