HTMLCollectionを配列に変換する最も効率的な方法


392

上記のコレクションのコンテンツを繰り返し処理して各項目を手動で配列にプッシュする以外に、HTMLCollectionを配列に変換するより効率的な方法はありますか?


10
「効率的」とはどういう意味ですか?パフォーマンスが最も良い場合、forループは一般にArray.prototype.sliceよりも高速です。ループはさまざまなブラウザー(つまり、すべてのブラウザー)でも機能するため、これらの基準で「最も効率的な方法」です。そして、それは非常に小さなコードです:for (var a=[], i=collection.length; i;) a[--i] = collection[i];それほど「con」はありません:-)
RobG '28年

@RobGありがとうございます-できれば+ 59kを差し上げます!;-)
スラッシュバック2016年

1
現在のブラウザのパフォーマンスを見ると、スライスはChromeを除いて、パフォーマンスの点でループにほとんど追いついています。多数の要素とループのわずかな最適化を使用すると、ループが非常に高速であるChromeを除いて、結果はほとんど同じです
RobG 2016年

@harpoが言及した両方のメソッドとパフォーマンスのjqueryテストを調べるjsperfテストを作成しました。私はjqueryが両方のjavascriptメソッドよりも少し遅く、最高のパフォーマンスがjsテストケース間で異なることを発見しました。Chrome 59.0.3071 / Mac OS X 10.12.5は使用Array.prototype.slice.callを優先し、Brave(Chrome 59.0.3071に基づく)は、複数の実行にわたる2つのjavascriptテストに実質的な違いはありません。jsperf.com/htmlcollection-array-vs-jquery-childrenを
NuclearPeon 2017

jsben.ch/h2IFA =>これを行う最も一般的な方法のパフォーマンステスト
EscapeNetscape

回答:


697
var arr = Array.prototype.slice.call( htmlCollection )

「ネイティブ」コードを使用しても同じ効果があります。

編集する

これは多くのビューを取得するため、(@ oriolのコメントに従って)次のより簡潔な式は実質的に同等であることに注意してください。

var arr = [].slice.call(htmlCollection);

しかし、@ JussiRのコメントに注意してください。「冗長」フォームとは異なり、プロセス内に空の、未使用の、実際には使用できない配列インスタンスが作成されます。コンパイラがこれについて行うことは、プログラマーのケンの外です。

編集する

ECMAScript 2015(ES 6)以降、Array.fromもあります

var arr = Array.from(htmlCollection);

編集する

ECMAScript 2015は、機能的に同等のスプレッド演算子も提供しますArray.from(ただしArray.from、2番目の引数としてマッピング関数をサポートしています)。

var arr = [...htmlCollection];

上記の両方がで動作することを確認しましたNodeList

上記のメソッドのパフォーマンス比較:http : //jsben.ch/h2IFA


7
これはIE6では失敗します。
ヒースボーダーズ

29
ショートカット[].slice.call(htmlCollection)も機能します。
Oriol 14

1
@ChrisNielsenはい私はそれについて誤解されていました。広がってごめんなさい。私もここでそれを述べたことに気づきませんでした。混乱を避けるためにコメントを削除しましたが、HTMLCollectionをスライスすると配列とコレクションの両方のように動作することをどこかで読んだ(または誤って読んだ)コンテキストです。完全に不正解です。
エリック・レッペン、2014年

3
[] .sliceショートカットは、未使用の空の配列インスタンスも作成するため、同等ではありません。ただし、コンパイラがそれを最適化できるかどうかはわかりません。
JussiR 2017

3
Array.fromつまりfrom、IE11ではサポートされていません。
Frank Conijn

86

これが最も効率的かどうかはわかりませんが、簡潔なES6構文は次のようになります。

let arry = [...htmlCollection] 

編集:別のもの、Chris_Fコメントから:

let arry = Array.from(htmlCollection)

9
さらに、ES6が追加Array.from()
Chris_F

4
最初のものに注意してください。バベルをトランスパイルするときに[... htmlCollection]が唯一の要素であるhtmlCollectionを含む配列を返すという微妙なバグがあります。
Marcel M.

3
配列拡散演算子はhtmlCollectionでは機能しません。NodeListにのみ適用されます。
ボビー

1
Array.fromつまりfrom、IE11ではサポートされていません。
Frank Conijn

ベンチマークのスプレッドオペレータのように見えるが早く出て、これらの2のである
RedSparr0w

20

Array.prototype同様に機能する、メソッドを取得するより簡潔な方法を見ました。HTMLCollectionオブジェクトをオブジェクトに変換する方法をArray以下に示します。

[] .slice.call(yourHTMLCollectionObject);

そして、コメントで述べたように、IE7以前などの古いブラウザーでは、次のような互換機能を使用する必要があります。

function toArray(x) {
    for(var i = 0, a = []; i < x.length; i++)
        a.push(x[i]);

    return a
}

私はこれが古い質問であることを知っていますが、受け入れられた答えは少し不完全だと感じました。だから私はこれをFWIWに捨てるつもりだと思った。


6

クロスブラウザーの実装については、prototype.js $A関数をご覧になることをお勧めします

1.6.1からコピー

function $A(iterable) {
  if (!iterable) return [];
  if ('toArray' in Object(iterable)) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

それは使用しませんArray.prototype.slice、それはすべてのブラウザでは利用できませんので、おそらく。フォールバックが上のJavaScriptループであるため、パフォーマンスはかなり悪いと思いiterableます。


2
OPは、「コレクションのコンテンツを繰り返し処理して、各項目を配列に手動でプッシュする」以外の方法を求めましたが、それがまさに$A関数がほとんどの場合に行っていることです。
Luc125

1
私がやろうとしていたのは、それを行うには良い方法がないということです。prototype.jsコードは、「toArray」メソッドを探すことができますが、その反復が最も安全な方法で失敗することを示しています
Gareth Davis

1
これにより、スパース配列に新しい未定義のメンバーが作成されます。割り当ての前にhasOwnPropertyテストがあるはずです。
RobG 2016年

3

これは、ここの情報(このスレッド)に基づく私の個人的な解決策です:

var Divs = new Array();    
var Elemns = document.getElementsByClassName("divisao");
    try {
        Divs = Elemns.prototype.slice.call(Elemns);
    } catch(e) {
        Divs = $A(Elemns);
    }

$ Aは、Gareth Davisの投稿で次のように説明されています。

function $A(iterable) {
  if (!iterable) return [];
  if ('toArray' in Object(iterable)) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

ブラウザが最善の方法をサポートしている場合は、そうですが、そうでない場合は、クロスブラウザを使用します。


一般に、try / catchが制御フローを管理する効率的な方法であるとは思いません。最初に関数が存在するかどうかを確認してから、どちらか一方を少し安く実行できます。
Patrick

2
Gareth Davisの回答と同様に、これはスパース配列に新しい未定義のメンバーを作成するため、に[,,]なり[undefined, undefined]ます。
RobG 2016年

こんなトラブルはまだありませんでした。3つの要素のコレクションを継ぎ合わせると、2つの要素を持つ配列になります。emptyがundefinedになると、それは少しJavaScriptの制限です、私はundefinedの代わりにnullを期待していたと思いますよね?
Gustavo

3

これは、以前のIEバージョンを含むすべてのブラウザで機能します。

var arr = [];
[].push.apply(arr, htmlCollection);

jsperfはまだダウンしているので、さまざまなメソッドのパフォーマンスを比較するjsfiddleを次に示します。https://jsfiddle.net/qw9qf48j/


試してみるvar args = (htmlCollection.length === 1 ? [htmlCollection[0]] : Array.apply(null, htmlCollection));
Shahar Shokrani

3

array-likeを効率的な方法で配列に変換するには、jQuery を利用できますmakeArray

makeArray:配列のようなオブジェクトを真のJavaScript配列に変換します。

使用法:

var domArray = jQuery.makeArray(htmlCollection);

少し余分:

配列オブジェクトへの参照を保持したくない場合(ほとんどの場合、HTMLCollectionsは動的に変更されるため、別の配列にコピーする方がよいです。この例では、パフォーマンスに細心の注意を払っています。

var domDataLength = domData.length //Better performance, no need to calculate every iteration the domArray length
var resultArray = new Array(domDataLength) // Since we know the length its improves the performance to declare the result array from the beginning.

for (var i = 0 ; i < domDataLength ; i++) {
    resultArray[i] = domArray[i]; //Since we already declared the resultArray we can not make use of the more expensive push method.
}

配列のようなものは何ですか?

HTMLCollection"array-like"オブジェクトであり、配列のようなオブジェクトは配列のオブジェクトに似ていますが、機能的な定義の多くがありません。

配列のようなオブジェクトは配列のように見えます。これらには、さまざまな番号付き要素と長さプロパティがあります。しかし、ここで類似性が停止します。配列のようなオブジェクトには配列の関数がなく、for-inループも機能しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.