2017-03-17 8 views
0

두 개의 다른 페이지에서 작동하는 북마크릿을 작성하려고합니다. 일단 요소를 잡으면 요소를 반복하고 처리 할 수 ​​있지만 두 개의 다른 페이지를 수용하기 위해 두 개의 다른 클래스 이름으로 DIV 목록을 컴파일하려고합니다. 나는이 시작 :일반 Javascript에서 getElementsByClassName의 결과를 어떻게 연결합니까?

> traces=[].concat.apply(document.getElementsByClassName('fullStacktrace'), 
         document.getElementsByClassName('msg')) 
[HTMLCollection[0], div#msg_2.msg.l1, ... div#msg_6460.msg.l1] 
> traces[0] 
[] 
> traces[1] 
<div class=​"msg l1" id=​"msg_2">​…​</div>​ 

그래서 getElementsByClassName이 두 페이지 작동 다른 페이지에있는 반면

> traces=[].concat.apply(document.getElementsByClassName('fullStacktrace'), 
         document.getElementsByClassName('msg')) 
[HTMLCollection[2]] 
> traces[0] 
[div.fullStacktrace, div.fullStacktrace] 
> traces[1] 
undefined 
> traces[0][0] 
<div class=​"fullStacktrace" style=​"height:​ auto;​">​…​</div>​ 

하지만 보이는 :

traces= 
    [].concat.apply(document.getElementsByClassName('fullStacktrace'), 
        document.getElementsByClassName('msg')) 

하지만 첫 번째 페이지에이 결과

concat.apply는 첫 번째 인수를 반복하지 않지만 두 번째 인수는 반복합니다.

그래서 내가 두 번 CONCAT를 사용하고 괄호 모든 외출 시도 :

traces=(
    (
    [].concat.apply(document.getElementsByClassName('fullStacktrace')) 
) 
    .concat.apply(document.getElementsByClassName('msg')) 
) 

을하지만, 심지어 낯선 가져옵니다 첫 페이지는 말했다 :

Array[1] 
> 0: HTMLCollection[0] 
    length: 0 
    > __proto__: HTMLCollection 
length: 1 
> __proto__: Array[0] 

다른 :

Array[1] 
> 0: HTMLCollection[283] // Lots of div#msg_3.msg.l1 sort of things in here 
    length: 1 
>__proto__: Array[0] 

div를 완벽하게 보완합니다.

두 그룹의 요소는 하나 또는 다른 페이지에만 있기 때문에 특정 경우에는 조건부를 사용할 수 있지만 위의 동작은 매우 놀랍기 때문에 이해하고 싶습니다. 어떤 아이디어? 참고로

, 이것은 CONCAT를 사용하려면 맥 크롬 버전 56.0.2924.87 (64 비트)

답변

2

에, 컬렉션은 배열입니다 인수 할 필요가있다. 다른 인수는 병합되지 않습니다. 당신은이에 대한 .slice()를 사용할 수 있습니다

traces= [].concat([].slice.call(document.getElementsByClassName('fullStacktrace')), 
        [].slice.call(document.getElementsByClassName('msg'))) 

현대 문법은 꽤 좋네요 만들 것입니다. 이것은 "확산"구문은 그것으로 분산 된 두 컬렉션의 내용에 새로운 배열을 만드는 데 사용 :

traces = [...document.getElementsByClassName('fullStacktrace'), 
      ...document.getElementsByClassName('msg')] 

또는 더 쉽게 polyfilled 무언가를 사용하려면 컬렉션을 변환 Array.from()을 사용할 수 있습니다 :

traces = Array.from(document.getElementsByClassName('fullStacktrace')) 
       .concat(Array.from(document.getElementsByClassName('msg')))) 

점수는 처음에 getElementsByClassName를 사용하지 않을 것입니다. .querySelectorAll을 사용합니다.

traces = document.querySelectorAll('.fullStacktrace, .msg') 

이 CSS가 사용하는 것과 동일한 선택기를 사용하므로 위의 선택이 실제로 각각의 클래스 요소를 선택하여 각각의 두 선택기의 그룹을 통과 : 당신은 더 나은 브라우저 지원 및 더 강력한 선택 기능을 얻을 .


자세한 설명

첫 번째 예 : 위의 문제의

내 설명도 간결했다. 여기에 귀하의 첫 번째 시도이다 :

traces = [].concat.apply(document.getElementsByClassName('fullStacktrace'), 
       document.getElementsByClassName('msg')) 

.concat() 작품은 this 값과 인수로 주어진 어떤 값을 가지고 가고, 하나의 배열로 결합하는 방법. 그러나 this 값 또는 인수 중 하나가 실제 Array 일 때 해당 내용을 한 수준의 결과로 평탄화합니다. HTMLCollection은 배열이 아니므로 추가해야하는 다른 값으로 간주되며 병합되지 않습니다.

.apply()은 호출 할 메서드의 값을 this으로 설정 한 다음 두 번째 인수의 멤버를 메서드에 개별 인수로 분산시킬 수 있습니다. 위 예제에서 은 .apply()의 첫 번째 인수로 전달되지 않고 .apply().concat()이 아니기 때문에 .apply()이기 때문에 .apply()의 두 번째 인수로 전달 된 결과가 결과로 병합되지 않습니다. .concat()의 관점에서, 두 번째 DOM 선택은 절대로 존재하지 않았습니다. msg 클래스를 가진 개별 DOM 요소 만 보았습니다.


번째 예 :

traces=(
    (
    [].concat.apply(document.getElementsByClassName('fullStacktrace')) 
) 
    .concat.apply(document.getElementsByClassName('msg')) 
) 

이 약간 다르다. 이 부분 [].concat.apply(document.getElementsByClassName('fullStacktrace'))은 첫 번째 예제와 동일한 문제가 있지만 그 결과로 HTMLCollection이 끝나지 않은 것으로 나타났습니다. 그 이유는 결국 .apply.concat(...을 묶었을 때 그 전화의 결과를 포기했기 때문입니다.

더 간단한 예를 들자. 이 작업을 수행 할 때 :

[].concat.apply(["bar"], ["baz", "buz"]) 

... [] 실제로 낭비 배열입니다. .concat() 방법을 사용하는 간단한 방법 일뿐입니다. .concat() 안에 ["bar"]this 값이되고, .apply()은 메소드의 개별 인수로 퍼지기 때문에 "baz""buz"이 개별 인수로 전달됩니다.
["foo"].concat.apply(["bar"], ["baz", "buz"]) 

이 ... "foo"이 결과에 아니라고주의 사항 :이에 간단한 예제를 변경하는 경우

당신이 더 명확하게 볼 수 있습니다. .concat()에 대한 지식이 없기 때문입니다. ["bar"], "baz""buz" 인 경우에만 알 수 있습니다.이했을 때

그래서 :

[].concat.apply(collection).concat.apply(collection) 

을 동일한 일을했다. 두 번째 .concat.apply은 기본적으로 첫 번째 데이터를 삭제하고 .apply()에 제공된 데이터 만 가지고 계속 수행하므로 첫 번째 수집은 나타나지 않습니다. 두 번째 호출에 .apply을 사용하지 않았다면 배열이 두 개가 아닌 HTMLCollection 인 배열로 끝났을 것입니다. document.getElementByClassName에 대한 호출이 반환하기 때문에

[].concat.apply(collection).concat(collection) 
// [HTMLCollection, HTMLCollection] 
+1

업 투표은'querySelectorAll' 솔루션을 제공하는 솔루션 제안

Pineda

+0

querySelectorAll에 대한 투표도 진행 중입니다. 그러나 괄호 안의 표현식이 [HTMLCollection [], HTMLCollection []]이되지 않은 이유와 첫 번째 표현식이 두 번째 HTMLCollection이 반복 된 이유가 무엇인지 이해할 수 없습니다 (첫 번째 경우에는 존재하지 않고 두 번째 경우에는 모든 div에서 추가됨), 첫 번째 HTMLCollection은 그대로 삽입되었습니다. –

+0

@ android.weasel :'.concat()'은 실제 배열 인 경우에만 콜렉션을 결과로 평평하게하기 때문에'HTMLCollection'은 다른 값으로 간주됩니다. 첫 번째 예제에서'.apply()'를 사용하면'.msg' 요소가 추가되었으므로'msg' 요소가 있다면'traces [1]'은'undefined'가되어서는 안됩니다. 'msg'가 없다면 추가 할 것이 없으므로'undefined '가됩니다. –

0

HTMLCollection보다는 Array 당신은 당신이보고있는 이상한 결과를 얻는 것입니다. 브라우저 호환성이 우려 비록입니다

traces= [].slice.call(document.getElementsByClassName('fullStacktrace')).concat([].slice.call(document.getElementsByClassName('msg'))) 

경우, here that may help for earlier versions of IE에서 다른 솔루션의 일부를 보라 : 우리가이 문제를 방지하기 위해 할 수있는 것은 배열에 HTMLCollection를 변환 한 다음과 같이 그들을 CONCAT입니다.

+0

해결 방법을 보내 주셔서 감사합니다. 그러나 두 번째 페이지의 배열이 [HTMLCollection [0], HTMLCollection [234]] 또는 이와 유사한 항목이 아닌 [HTMLCollection, div, div, div]가되는 이유는 무엇입니까? 하나의 HTMLCollection을 다른 HTMLCollection에 연결하려고하지 않고 [*] * 배열에 * 둘 다 넣으려는 것을 감안할 때? –

0

설명 :

Document.getElementsByClassName가 제공하는 클래스 이름과 일치 요소 라이브 HTMLCollection를 반환합니다. 배열과 같은 객체이지만 이 아니고 배열이입니다.

그래서 초기 배열은 요소 배열을 병합하는 대신 HTML 요소의 두 라이브 목록을 병합하려고했습니다.

Array#slice()을 사용하여 고체 (비 라이브 배열)를 작성하고 직접 두 배열을 병합 할 수 있습니다 :

var fullStacktrace = [].slice.call(document.getElementsByClassName('fullStacktrace'), 0), 
    msg = [].slice.call(document.getElementsByClassName('msg'), 0), 

    mergedDivs = fullStacktrace.concat(msg); 
+0

첫 번째 및 두 번째 getElement 호출에 대해 왜 연결이 다르게 작동하는지 아직 명확하지 않습니다. 첫 번째는 간단히 삽입되며 두 번째는 반복됩니다. 두 번째 괄호로 묶인 표현식에서 최종 배열에 HTMLCollection이 하나만있는 이유는 무엇입니까? –