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

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

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

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

Q&A

解決済

2回答

4760閲覧

NodeListやHTMLCollectionの配列化

flat

総合スコア617

JavaScript

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

0グッド

0クリップ

投稿2016/03/24 14:09

編集2016/03/25 11:36

NodeListやHTMLCollectionといったArray-Like ObjectをArray Objectに変換すると、ループ処理などの時に高速に処理できるという旨の情報を目にしたのですが、これはgetElementsBy~などで取得したArray-Like Objectに対して「とりあえずやっておく」というおまじない的なレベルで利用できるものと見て良いのでしょうか?
また、Array Objectにすることによる他のメリットやデメリットなどもあればお聞きしたいです。

追記
実際に100個の要素をgetElementsByClassNameで取得してループさせ、classNameプロパティを使ってクラスを追加するという内容で処理時間を比較して計測したところ、2倍以上の処理時間を短縮を確認できました。
また、element.className = element.className + ' check';を削除するとその差がより大きくなり、少なくとも20倍の差が開きました。
この結果からすると、高速に処理できるという点は間違いないと見て良いのでしょうか。
それとも、この計測の仕方が適切ではないだけでしょうか?
ちなみに、使用したブラウザはGoogle Chrome 49です。

追記
一応計測結果をコードの方に追記

HTML

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4<meta charset="utf-8"> 5<title>example</title> 6<meta http-equiv="X-UA-Compatible" content="IE=edge"> 7<meta name="viewport" content="width=device-width, initial-scale=1.0"> 8<style type="text/css"> 9.check { 10 color: red; 11} 12</style> 13<script type="text/javascript"> 14;( function () { 15 'use strict'; 16 function func(event) { 17 var doc = event.target; 18 19 console.time('get'); 20 21 // getElementsByTagName = HTMLCollection 22 var elements = doc.getElementsByTagName('p'); 23 24 // getElementsByClassName = HTMLCollection 25 //var elements = doc.getElementsByClassName('element'); 26 27 // querySelectorAll = NodeList 28 //var elements = doc.querySelectorAll('.element'); 29 30 // Array 31 //var elements = Array.prototype.slice.call(doc.getElementsByClassName('element')); 32 33 console.timeEnd('get'); 34 35 var l = elements.length; 36 var element; 37 38 console.time('for'); 39 for (var i = 0; i < l; i++) { 40 element = elements[i]; 41 element.className = element.className + ' check'; 42 } 43 console.timeEnd('for'); 44 } 45 46 document.addEventListener('DOMContentLoaded', func, false); 47 48 /* 49 * 取得(処理時間が短い順) 50 * 51 * getElementsByTagName & getElementsByClassName 52 * 要素数1000: 約0.03ms 53 * 要素数10000: 約0.03ms 54 * 55 * querySelectorAll 56 * 要素数1000: 約0.1ms 57 * 要素数10000: 約0.4ms 58 * 59 * Array(Array.prototype.slice.call(HTMLCollection)で配列に変換) 60 * 要素数1000: 約2.5ms 61 * 要素数10000: 約7ms 62 * 要素の取得時間というよりは、ほぼ変換処理にかかる時間 63 */ 64 65 /* 66 * forループ処理(処理時間が短い順) 67 * 68 * Array 69 * 要素数1000: 約0.8ms 70 * 要素数10000: 約9ms 71 * 72 * getElementsByTagName 73 * 要素数1000: 約2.5ms 74 * 要素数10000: 約12ms 75 * 76 * querySelectorAll 77 * 要素数1000: 約2.6ms 78 * 要素数10000: 約13ms 79 * 80 * getElementsByClassName 81 * 要素数1000: 約15ms 82 * 要素数10000: 約756ms 83 */ 84}()); 85</script> 86</head> 87<body> 88<div class="elements"> 89 <!-- 100 element --> 90 <p class="element">element</p> 91 <p class="element">element</p> 92 <p class="element">element</p> 93 <p class="element">element</p> 94 <p class="element">element</p> 95 <p class="element">element</p> 96 <p class="element">element</p> 97 <p class="element">element</p> 98 <p class="element">element</p> 99 <p class="element">element</p> 100 <p class="element">element</p> 101 <p class="element">element</p> 102 <p class="element">element</p> 103 <p class="element">element</p> 104 <p class="element">element</p> 105 <p class="element">element</p> 106 <p class="element">element</p> 107 <p class="element">element</p> 108 <p class="element">element</p> 109 <p class="element">element</p> 110 <p class="element">element</p> 111 <p class="element">element</p> 112 <p class="element">element</p> 113 <p class="element">element</p> 114 <p class="element">element</p> 115 <p class="element">element</p> 116 <p class="element">element</p> 117 <p class="element">element</p> 118 <p class="element">element</p> 119 <p class="element">element</p> 120 <p class="element">element</p> 121 <p class="element">element</p> 122 <p class="element">element</p> 123 <p class="element">element</p> 124 <p class="element">element</p> 125 <p class="element">element</p> 126 <p class="element">element</p> 127 <p class="element">element</p> 128 <p class="element">element</p> 129 <p class="element">element</p> 130 <p class="element">element</p> 131 <p class="element">element</p> 132 <p class="element">element</p> 133 <p class="element">element</p> 134 <p class="element">element</p> 135 <p class="element">element</p> 136 <p class="element">element</p> 137 <p class="element">element</p> 138 <p class="element">element</p> 139 <p class="element">element</p> 140 <p class="element">element</p> 141 <p class="element">element</p> 142 <p class="element">element</p> 143 <p class="element">element</p> 144 <p class="element">element</p> 145 <p class="element">element</p> 146 <p class="element">element</p> 147 <p class="element">element</p> 148 <p class="element">element</p> 149 <p class="element">element</p> 150 <p class="element">element</p> 151 <p class="element">element</p> 152 <p class="element">element</p> 153 <p class="element">element</p> 154 <p class="element">element</p> 155 <p class="element">element</p> 156 <p class="element">element</p> 157 <p class="element">element</p> 158 <p class="element">element</p> 159 <p class="element">element</p> 160 <p class="element">element</p> 161 <p class="element">element</p> 162 <p class="element">element</p> 163 <p class="element">element</p> 164 <p class="element">element</p> 165 <p class="element">element</p> 166 <p class="element">element</p> 167 <p class="element">element</p> 168 <p class="element">element</p> 169 <p class="element">element</p> 170 <p class="element">element</p> 171 <p class="element">element</p> 172 <p class="element">element</p> 173 <p class="element">element</p> 174 <p class="element">element</p> 175 <p class="element">element</p> 176 <p class="element">element</p> 177 <p class="element">element</p> 178 <p class="element">element</p> 179 <p class="element">element</p> 180 <p class="element">element</p> 181 <p class="element">element</p> 182 <p class="element">element</p> 183 <p class="element">element</p> 184 <p class="element">element</p> 185 <p class="element">element</p> 186 <p class="element">element</p> 187 <p class="element">element</p> 188 <p class="element">element</p> 189 <p class="element">element</p> 190</div> 191</body> 192</html>

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

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

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

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

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

guest

回答2

0

ベストアンサー

URLのページに書かれている通り、静的な配列に変換したほうが早いですね

変換のメリットは、配列メソッドが使えるようになったり、動的でないこと

例えば

javascript

1var list = document.getElementsByTagName("li") 2for(var i=0;i<list.length;i++){ 3 list[i].remove() 4}

というのはうまくいかないです

動的なので remove した瞬間にずれてきます
配列なら [0] を remove したら [0] に remove 済みがあって [1] 以降に remove されていないのがありますが、 動的な場合は、 [0] に もともと [1] だったのが入ります
shift() したみたいになります

デメリットはこれも動的でなくなること
動的だと、上の例みたいな remove されたときに、何番目の要素がすでに remove されてるなんて気にしないで済みます
HTMLCollection の中にいるのは全部ツリーに属しています

動的であって欲しい使い方をしないならとりあえず 変換しますね
querySelectorAll で取得できる NodeList は静的なのでこっちは配列メソッド使うくらいしかメリットないです

投稿2016/03/24 15:37

ryls-nmm

総合スコア633

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

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

flat

2016/03/24 16:34

回答して下さりありがとうございます。 動的なオブジェクトは、DOMに加えられた変更がそのままオブジェクトにも反映される。 配列化した静的なオブジェクトは動的なオブジェクトの要素をコピーした配列なので、要素の変更などは出来てもDOMツリーの反映はされず、要素は欠けたままになる。 という理解で大丈夫ですかね……? 取得したオブジェクトに削除などの変更を加えなければ配列化しておいて良さそうですね。 削除などをした場合もインデックスを詰めたら大丈夫そうな気がします。 あまり自信はありませんが……。
ryls-nmm

2016/03/24 17:08

だいたいそんなとこです 削除に限らず「取得した条件にあっているか」なので、質問の追記にあるものだと、 `element` というクラスのものを取得しているので、`elements ` のHTMLCollection には `element` というクラスがあるものだけになります 要素は削除せずに、ひとつ目のelementのクラス名を消すと `elements` の要素数は 99 個になります 上で書いたコードと同じ感じことですが、質問の追記コードで element.className = element.className + ' check'; とあるのを element.className = ""; こうしてしまうと、element を持たないクラスが飛び飛びでできてしまいます あと、先に length を取得しているので 途中から undefined のプロパティを見に行ってエラーになります この辺りを把握しておけば大丈夫かと思います ほとんどの場合は querySelector で NodeList を取得するでしょうし
flat

2016/03/25 11:29

確かに、取得した条件と処理内容が合っているのかはちゃんと確認しないといけませんね。 取得した情報がどういうものなのかを正しく認識することは大事ですね……。 ちなみに処理時間に関しては処理の内容にもよるとは思いますが、要素が1000以上あったり、何度もループで参照するようなケースでなければあまり気にしなくて良さそうだと思いました。 通常はそのままgetElementsBy系のメソッドでHTMLCollectionを取得して、静的なオブジェクトが欲しければquerySelectorAllでNodeListを取得し、配列として扱いたい時は処理内容に注意した上で配列化するという風にしようと思います。 回答して下さったお二人に感謝致します。 ありがとうございました。
guest

0

配列化する事で高速化される手法は聞いたことがありませんし、原理的にも速くなるとは思えません。
繰り返し処理で速度を競うなら「while > for > Array.prototype.forEach」となるので配列化せずとも繰り返し文を高速に処理できます。

配列化するメリットは Array.prototype 上にあるメソッドを何度も呼び出す場合に Function#callthis 値を指定するコストを支払わなくて良い事ですね。
配列化するデメリットは変換コストが余計にかかる事です。
Array.prototype 上にあるメソッドを呼び出す回数が著しく多く、メリットがデメリットを上回る状況で使用を検討して下さい。

Re: flat さん

投稿2016/03/24 14:29

think49

総合スコア18162

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

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

flat

2016/03/24 15:13

回答して下さりありがとうございます。 Array.prototype が利用できるのは、回答して下さったcallメソッドも含め、使い方次第で何か活用できそうですね。 ちなみに、この質問は以下の投稿を見て気になったのでさせて頂きました。 http://inside.pixiv.net/entry/2015/12/23/120000 自分なりにも色々と調べてみたのですが、今ひとつすっきりしないので「そうだ、実際に計測したら良いんだ」という事で計測してみたところ、配列化した処理をループさせると処理時間が大幅に短縮されました。 質問の方にも追記しておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問