Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome getElementsByTagName returning HTMLCollection vs NodeList

I've found the the JavaScript function getElementsByTagName is returning different data depending on the browser. Chrome sends back and HTML collection that is longer (really, better, IMO) than Firefox, IE or Chromium.

I'll outline my findings below. My question is essentially "Why did Chrome changes this, will other browsers do this as well (when?), and how reliable is the returned length attribute?"

Comparing Chrome (Version 34.0.1847.116 m) vs. Chromium (Version 33.0.1750.152 Ubuntu 13.10 (256984)). I do notice that this Chromium build is a bit behind Chrome (v33 vs v34), so it may be heading this way as well in the Ubuntu Chromum build, but it at least helped me compare what's going on here.

Consider the following code block:

<script type='text/javascript'>
function getElements(){
  var x=document.getElementsByTagName("input");
  console.log(x.length);
  console.log(x);
}
</script>
<form>
<input type="text" size="20" id='test1'><br>
<input type="text" size="20" id='test2'><br>
<input type="text" size="20" id='test3'><br><br>
<input type="button" onclick="getElements()" value="How many input elements?">
</form>

Running the above in Chromium and other browsers gives result showing that the length is 4, and the data returned is an indexed array, something like:

[input#test1, input#test2, input#test3, input, item: function] 0: input#test1 1: input#test2 2: input#test3 3: input length: 4 __proto__: NodeList

Chrome returns a similar but expanded result array:

[input#test1, input#test2, input#test3, input, test1: input#test1, test2: input#test2, test3: input#test3, item: function, namedItem: function] 0: input#test1 1: input#test2 2: input#test3 3: input length: 4 test1: input#test1 test2: input#test2 test3: input#test3 __proto__: HTMLCollection

Notice that in both cases, the length is 4, but Chromium includes each input element a second time, indexed by the element's ID attribute instead of the index key. Chrome is returning an HTMLCollection where Chromium supplies a NodeList.

In the past I've processed these arrays with for x in y syntax, plus some validation, like so:

var inputs = document.getElementsByTagName('input');
for (x in inputs){
  if(inputs[x].id != undefined){
  }
}

The conclusion I've drawn is that to use the results this way:

var inputs = document.getElementsByTagName('input');
for (x=0; x<inputs.length; x++){
}

Either way, you access your elements with inputs[x] but using the second method we guarantee that x is always one of the integers that we use as a key. In the first method, x would be an integer-key, then the string 'length', then any ID strings.

like image 977
Matthew Poer Avatar asked Apr 23 '14 13:04

Matthew Poer


1 Answers

From the developer firefox documentation:

While the W3C DOM 3 Core specification says elements is a NodeList that was simply because of a an attempt to have the "core" specification not depend on the "html" specification at that time. The DOM 4 draft says that elements is an HTMLCollection.

Gecko/Firefox currently returns a NodeList (Bug 162927) but starting with Gecko/Firefox 19, this method will return HTMLCollection (Bug 799464). Internet Explorer returns a HTMLCollection. WebKit returns a NodeList. Opera also returns a NodeList, but with a namedItem method implemented, which makes it similar to a HTMLCollection.

like image 173
bastos.sergio Avatar answered Oct 20 '22 01:10

bastos.sergio