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

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

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

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

Q&A

解決済

3回答

1022閲覧

JavaScript 繰り返し同じ処理を書いてしまっている部分を修正したいです

pecoro0321

総合スコア10

JavaScript

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

0グッド

0クリップ

投稿2019/07/06 23:38

編集2019/07/07 00:19

前提・実現したいこと

同じ記述を繰り返してしまっている部分をまとめられるかどうか知りたいです。

該当のソースコード

audioタグのロード状況を確認するために下記のコードを記述しました。
同じコードを5回書けば想定した動きにはなるのですが、
5回書いてしまっている部分をまとめたいと思い、後述の「試したこと」のように書き直そうとしたところ
フラグの変更の仕方がわからず、うまくいきませんでした。

JavaScript

1const audioElems = document.getElementsByTagName('audio'); 2 3const audio01 = document.getElementById('audio01'); 4const audio02 = document.getElementById('audio02'); 5const audio03 = document.getElementById('audio03'); 6const audio04 = document.getElementById('audio04'); 7const audio05 = document.getElementById('audio05'); 8 9let loadedAudio01 = false; 10let loadedAudio02 = false; 11let loadedAudio03 = false; 12let loadedAudio04 = false; 13let loadedAudio05 = false; 14 15let loadedAudiosLength = 0; 16let loadedAudioAll = false; 17 18// loadedAudio01がfalseであればロードを開始する 19if (!loadedAudio01) { 20 audio01.load(); 21 audio01.addEventListener("loadstart", function () { 22 // ロードスタート後の処理 23 console.log(audio01.id + ' is now loading...'); 24 }) 25 audio01.addEventListener("canplaythrough", function () { 26 // ロード完了後の処理 27 console.log(audio01.id + ' is loaded.'); 28 loadedAudio01 = true; 29 loadedAudiosLength += 1; 30 if (loadedAudiosLength === audioElems.length) { 31 // すべての要素をロードした後の処理 32 loadedAudioAll = true; 33 console.log('All contents are loaded.'); 34 } 35 }) 36} 37// ↓この後、「01」の部分を02〜05に変更した同じコードを4回記述 38 39//出力結果 40// audio01 is now loading... 41// audio02 is now loading... 42// audio03 is now loading... 43// audio04 is now loading... 44// audio05 is now loading... 45// audio02 is loaded. 46// audio01 is loaded. 47// audio03 is loaded. 48// audio04 is loaded. 49// audio05 is loaded. 50// All contents are loaded.

試したこと

JavaScript

1// 変数定義は省略 2 3const audioElems = [audio01,audio02,audio03,audio04,audio05]; 4const loadedAudioTriggers = [loadedAudio01, loadedAudio02, loadedAudio03, loadedAudio04, loadedAudio05]; 5 6for (let i = 0; i < audioElems.length; i++){ 7 if (!loadedAudioTriggers[i]) { 8 audioElems[i].load(); 9 audioElems[i].addEventListener("loadstart", function () { 10 console.log(audioElems[i].id + ' is now loading...'); 11 }) 12 audioElems[i].addEventListener("canplaythrough", function () { 13 console.log(audioElems[i].id + ' is loaded.'); 14 loadedAudioTriggers[i] = true; //これでは駄目だけど、やり方がわからない 15 loadedAudiosLength += 1; 16 if (loadedAudiosLength === audioElems.length) { 17 loadedAudioAll = true; 18 console.log('All contents are loaded.'); 19 console.log('loadedAudio01は' + loadedAudio01); 20 console.log('loadedAudio02は' + loadedAudio02); 21 console.log('loadedAudio03は' + loadedAudio03); 22 console.log('loadedAudio04は' + loadedAudio04); 23 console.log('loadedAudio05は' + loadedAudio05); 24 } 25 }) 26 } 27} 28 29//出力結果 30// audio01 is now loading... 31// audio02 is now loading... 32// audio03 is now loading... 33// audio04 is now loading... 34// audio05 is now loading... 35// audio02 is loaded. 36// audio01 is loaded. 37// audio03 is loaded. 38// audio04 is loaded. 39// audio05 is loaded. 40// All contents are loaded. 41// loadedAudio01はfalse ←本当はload後はtrueに変更したい 42// loadedAudio02はfalse 43// loadedAudio03はfalse 44// loadedAudio04はfalse 45// loadedAudio05はfalse

補足情報

下記の質問にご回答をいただき、間違っている理由はわかったのですが、上記の場合どのように修正してよいかわからず、
周辺のコードを追加して再度質問させていただきました。何卒よろしくお願いいたします。
https://teratail.com/questions/198715

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

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

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

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

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

think49

2019/07/07 00:14

変数 loadedAudiosLength が未定義のようです
pecoro0321

2019/07/07 00:19

すみません、追加修正いたしました。ご指摘ありがとうございます。
guest

回答3

0

ベストアンサー

audio01, audio02, ...
loadedAudio01, loadedAudio02, ...
という変数を作らず、audioElemsとloadedAudioTriggersだけで操作するようにしたらいいのでは。

javascript

1const loadedAudioTriggers = [false, false, false, false, false];

とか、

javascript

1const loadedAudioTriggers = (function() { 2 const array = []; 3 for (let i = 0; i < 5; i++) { 4 array.push(false); 5 } 6 return array; 7}());

など・・・
そうすれば、

console.log('loadedAudio01は' + loadedAudio01);
console.log('loadedAudio02は' + loadedAudio02);
console.log('loadedAudio03は' + loadedAudio03);
console.log('loadedAudio04は' + loadedAudio04);
console.log('loadedAudio05は' + loadedAudio05);

これもすっきりして、

javascript

1for (let j = 0; j < loadedAudioTriggers.length; j++) { 2 console.log('loadedAudio' + j + 'は' + loadedAudioTriggers[j]); 3}

となります。

投稿2019/07/07 02:21

編集2019/07/07 02:25
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

pecoro0321

2019/07/08 11:06

配列の要素にtrue/falseを入れるべきところを間違ってしまっていたのですね。ご指摘いただいた部分を修正して無事に動くようにできました。ありがとうございました。
退会済みユーザー

退会済みユーザー

2019/07/08 12:23 編集

ちなみにですが、 loadedAudio01, loadedAudio02, ...みたいな変数の作り方は、後で増減したくなるなどしたときに困るのでやめましょう、というのと、 let loadedAudio01 = false; let loadedAudio02 = false; let loadedAudio03 = false; let loadedAudio04 = false; let loadedAudio05 = false; const loadedAudioTriggers = [loadedAudio01, loadedAudio02, loadedAudio03, loadedAudio04, loadedAudio05]; という書き方で、おそらくloadedAudioTriggers を「変数の配列」か何かと思われていますが、実際はloadedAudioxxは全部プリミティブ型なので、実際にはfalseの配列にしかなっていない、というのも覚えておいてください。(前回の質問も見ましたが、そこにある回答でも似たようなことを書いてた方がいらっしゃったと思いますが念の為)
pecoro0321

2019/07/09 13:38

大変勉強になります!確かに、前回の質問からまったく成長していない間違い方をしていました。。ありがとうございます!
guest

0

JavaScript

1loadedAudioTriggers[i] = true; //これでは駄目だけど、やり方がわからない

それが配列である事は理解していると思いますので、audioElems, loadedAudioTriggers と同様に初期値として配列を定義してください。

Re: pecoro0321 さん

投稿2019/07/07 01:02

think49

総合スコア18164

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

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

think49

2019/07/07 01:08 編集

編集画面に回答文はありますが、外面上は出力されないteratailシステムのバグです。 編集画面で本文に何も変更を加えずに [更新する] ボタンを押下できなくなりました(今までは出来ました)。 本バグは未修正のようなので、バグ報告の為に本回答は編集せず、コメント欄に回答本文を書きます。
pecoro0321

2019/07/08 12:18

ご回答ありがとうございました!配列の要素にtrue/falseを入れるべきを、トリガー名を入れてしまっていたのですね。。名前と値をいつも混同してしまっている気がするので、また勉強したいと思います。
guest

0

やり方はいろいろあると思いますが、私ならこう書きます。ご参考になれば幸いです。
ループの中のイベントリスナから、ループの外の配列にアクセスするのは面倒なので、Objectで読み込みの状態を管理するようにしています。

js

1// 読み込み状態を管理する Object 2let loadedFlagState = {}; 3 4audioElems.forEach(elm => { 5 // 読み込みが完了しているなら、StateをTrueにして次のループへ 6 if(elm.readyState === 4) { 7 loadedFlagState[elm.id] = true; 8 confirmAllContentsLoadingAreCompleted(audioElems, loadedFlagState); 9 return; 10 } 11 12 elm.addEventListener('loadstart', evt => { 13 console.log(`${evt.currentTarget.id} is loading now.`); 14 }); 15 elm.addEventListener('canplaythrough', evt => { 16 console.log(`${evt.currentTarget.id} has loaded.`); 17 loadedFlagState[elm.id] = true; 18 confirmAllContentsLoadingAreCompleted(audioElems, loadedFlagState); 19 }); 20 21 // Stateに {audioXX: false} をセットする。読み込みが完了したら true にする 22 loadedFlagState[elm.id] = false; 23 24 // 読み込み開始 25 try { 26 elm.load(); 27 } catch(e) { 28 console.error(`Error on ${elm.id}: ${e.message}`); 29 } 30}); 31 32function confirmAllContentsLoadingAreCompleted() { 33 if(Object.keys(loadedFlagState).filter(key => loadedFlagState[key]).length === audioElems.length) { 34 console.log('All contents have loaded.'); 35 } 36}

以下、コメントを受けて追記します。 (コメントに対するコメントではコードブロックが使用できないため)
Jul 9, 2019 08:03 AM

loadedFlagState = {

'audio01':'false',
'audio02':'false',
'audio03':'false',
'audio04':'false',
'audio05':'false'
}というようなオブジェクトを生成しているという理解で合っていますでしょうか?

はい、概ねあっていますが、true/falseは文字列ではないのでシングルクォートでは囲みません。生成している Objectは次のとおりです。

js

1loadedFlagState = { 2 'audio01': false, 3 'audio02': false, 4 'audio03': false, 5 'audio04': false, 6 'audio05': false 7}

下記の部分はどういった状態の要素を意味しているのでしょうか?

Object.keys(loadedFlagState).filter(key => loadedFlagState[key])

詳細は1つ1つMDMなどを参照していただきたいですが、
Object.keys(obj)obj が持つキーを配列で取得するメソッドで、今回は ['audio01', 'audio02' ... 'audio05'] が得られます。

Array.prototype.filter(callback(element, index, array)) は配列に条件を指定してフィルターを掛けるメソッドで、条件をcallbackで指定します。アロー関数で記載していますが省略せずに書くと、

js

1[ 2 'audio01', 3 'audio02', 4 'audio03', 5 'audio04', 6 'audio05' 7].filter(function(key) { 8 return loadedFlagState[key]; 9});

になります。たとえば loadedFlagState['audio01']loadedFlagState['audio02']true (= 読み込みが完了している) で、ほかは false の場合、 ['audio01', 'audio02'] が得られます。
['audio01', 'audio02'].lengthaudioElems.length とは当然一致しないので、まだ読み込みが完了していないことを意味します。

余談ですが、

js

1function confirmAllContentsLoadingAreCompleted() { 2 if(Object.keys(loadedFlagState).filter(key => loadedFlagState[key]).length === audioElems.length) { 3 console.log('All contents have loaded.'); 4 } 5}

と書くよりも、

js

1function confirmAllContentsLoadingAreCompleted() { 2 if(Object.keys(loadedFlagState).filter(key => loadedFlagState[key]).length !== audioElems.length) return; 3 console.log('All contents have loaded.'); 4}

としたほうが、無駄なインデントが省けてbetterでしたね、失礼しました。

投稿2019/07/07 04:14

編集2019/07/08 23:14
thyda.eiqau

総合スコア2982

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

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

pecoro0321

2019/07/08 11:58

ありがとうございます!!大変参考になります。 loadedFlagState = { 'audio01':'false', 'audio02':'false', 'audio03':'false', 'audio04':'false', 'audio05':'false' }というようなオブジェクトを生成しているという理解で合っていますでしょうか? 1点質問したいのですが、下記の部分はどういった状態の要素を意味しているのでしょうか? Object.keys(loadedFlagState).filter(key => loadedFlagState[key]) ご教授いただけますと幸いです。
pecoro0321

2019/07/09 13:33

大変丁寧なご説明ありがとうございました!「条件をcallbackで指定する」という意味がはじめ難しかったのですが、MDNの説明で「callbackは配列の各要素に対して実行するテスト関数です。この関数が true を返した要素は残され、false を返した要素は取り除かれます。」というのを読んで理解できました!アロー関数だとreturnも省略できるのですね。大変勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問