HTMLCollection을 배열로 변환하는 가장 효율적인 방법


391

컬렉션의 내용을 반복하고 각 항목을 수동으로 배열에 넣는 것 외에 HTMLCollection을 배열로 변환하는보다 효율적인 방법이 있습니까?


10
"효율적인"이란 무엇입니까? 성능이 가장 좋은 경우 for 루프는 일반적으로 Array.prototype.slice 보다 빠릅니다 . 루프는 광범위한 브라우저 (즉, 모두)에서도 작동하므로 이러한 기준 따라 "가장 효율적인 방법"입니다. 그리고 그것은 아주 작은 코드입니다. for (var a=[], i=collection.length; i;) a[--i] = collection[i];그래서 "con"이 많지 않습니다 :-)
RobG

@RobG 감사합니다-가능하다면 + 59k를 드리겠습니다! ;-)
슬래시 백

1
보면 현재 브라우저 성능 , 슬라이스는 주로 크롬을 제외하고, 성능면에서 루프를 따라 잡았습니다. 더 많은 수의 요소와 약간의 루프 최적화를 사용하면 루프가 훨씬 빠른 Chrome을 제외하고 결과는 거의 동일합니다 .
RobG

@harpo가 언급 한 메소드와 성능에 대한 jquery 테스트를 모두 보는 jsperf 테스트를 만들었습니다. jquery가 자바 스크립트 방법보다 약간 느리고 js 테스트 사례마다 최고의 성능이 다릅니다. Chrome 59.0.3071 / Mac OS X 10.12.5는 선호 Array.prototype.slice.call하고 Brave (Chrome 59.0.3071 기반)는 여러 실행에 대한 두 자바 스크립트 테스트간에 거의 차이가 없습니다. 참조 jsperf.com/htmlcollection-array-vs-jquery-children
NuclearPeon

jsben.ch/h2IFA => 가장 일반적인 방법에 대한 성능 테스트
EscapeNetscape

답변:


696
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두 번째 인수로 매핑 기능 을 지원하는 경우도 있지만 ).

var arr = [...htmlCollection];

위의 두 가지 작업 모두에 대해 확인했습니다 NodeList.

언급 된 방법에 대한 성능 비교 : http://jsben.ch/h2IFA


7
이것은 IE6에서 실패합니다.
Heath Borders

29
바로 가기 [].slice.call(htmlCollection)도 작동합니다.
Oriol

1
@ChrisNielsen 그래, 나는 그것에 대해 잘못 알고 있었다. 널리 퍼져서 죄송합니다. 나는 여기에도 언급했다는 것을 몰랐다. 혼란을 피하기 위해 주석을 삭제했지만 컨텍스트에서 HTMLCollection을 슬라이스하면 배열과 컬렉션처럼 작동한다는 내용을 읽었습니다 (또는 잘못 읽었습니다). 완전히 틀렸다.
Erik Reppen 2016 년

3
[] .slice 바로 가기는 사용되지 않는 빈 배열 인스턴스도 생성하므로 동일하지 않습니다. 그러나 컴파일러가 최적화 할 수 있는지 확실하지 않습니다.
JussiR

3
Array.fromfrom, IE11에서는 지원되지 않습니다.
Frank Conijn

86

이것이 가장 효율적인지 확실하지 않지만 간결한 ES6 구문은 다음과 같습니다.

let arry = [...htmlCollection] 

편집 : Chris_F 의견의 또 다른 하나 :

let arry = Array.from(htmlCollection)

9
또한 ES6는 다음을 추가합니다.Array.from()
Chris_F

4
첫 번째 것을 조심하십시오. babel로 변환 할 때 미묘한 버그가 있습니다. 여기서 [... htmlCollection]은 유일한 요소 인 htmlCollection을 가진 배열을 반환합니다.
Marcel M.

3
htmlCollection에서는 배열 스프레드 연산자가 작동하지 않습니다. NodeList에만 적용됩니다.
Bobby

1
Array.fromfrom, 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모든 브라우저에서 사용할 수 없기 때문에 아마 사용하지 않습니다 . 폴 백이 자바 스크립트 루프이기 때문에 성능이 상당히 나쁩니다 iterable.


2
OP는 "그 컬렉션의 내용을 반복하고 각 항목을 수동으로 배열에 넣는 것"이외의 다른 방법을 요구했지만, 그것이 바로 그 $A기능이 대부분의 시간에하는 일입니다.
Luc125

1
필자가 시도한 요점은 그것을 할 수있는 좋은 방법이 없다는 것입니다. prototype.js 코드는 'toArray'메소드를 찾을 수 있지만 가장 안전한 경로를 반복하지 못한다는 것을 보여줍니다.
Gareth Davis

1
이것은 희소 배열에 정의되지 않은 새 멤버를 작성합니다. 할당 전에 hasOwnProperty 테스트 가 있어야 합니다.
RobG

3

이것은 여기의 정보 (이 스레드)를 기반으로하는 개인 솔루션입니다.

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

가레스 데이비스 (Gareth Davis)가 그의 직책에서 $ A를 묘사 한 곳 :

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

아직 이런 종류의 문제가 발생하지 않았습니다. 3 개의 요소 컬렉션으로 이음새가 생기고 2 개의 요소가있는 배열이 만들어집니다. empty가 undefined가되면 약간의 JavaScript 제한 사항입니다. 정의되지 않고 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

효율적인 방식으로 배열과 같은 배열을 배열로 변환하기 위해 jQuery를 사용할 수 있습니다 makeArray.

makeArray : 배열과 유사한 객체를 실제 JavaScript 배열로 변환합니다.

용법:

var domArray = jQuery.makeArray(htmlCollection);

약간의 추가 :

배열 객체에 대한 참조를 유지하지 않으려는 경우 (대부분의 HTMLCollection은 동적으로 변경되어 다른 배열로 복사하는 것이 더 좋습니다)이 예제에서는 성능에주의를 기울입니다.

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"객체이며, 배열과 유사한 객체는 배열의 객체와 유사하지만 많은 기능적 정의가 없습니다.

배열 같은 객체는 배열처럼 보입니다. 번호가 매겨진 요소와 길이 속성이 있습니다. 그러나 그것이 유사성이 멈추는 곳입니다. 배열과 같은 객체에는 Array의 기능이 없으며 for-in 루프는 작동하지 않습니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.