Wednesday, May 10, 2006

Looping through Javascript object properties

Update July 2016: This post is really old and obsolete. In it I was describing getting both attributes of DOM elements and properties of the element object, a thing that should rarely be useful. Even so, I will update the post with the better way of doing this.

First of all, looping through the properties of a Javascript object:
// for ... in ...
for (var key in obj) {

// using Object.keys (IE9+) and a normal for loop
var keys=Object.keys(obj);
for (var i=0; i<keys.length; i++) {
    var key=keys[i];

// using the Array.prototype.forEach function (IE9+)
Object.keys(obj).forEach(function(key) {

// for ... of ... from the new ES6 specification
for (var key of Object.keys(obj)) {

All of the methods above are similar, but not exactly the same. For example, the loop goes over all the properties of an object, including those coming from its prototype. Object.keys (the other three methods, which all basically iterate over an array) only takes the set properties of the object itself. One can determine if an object has the property or it comes from the prototype using Object.prototype.hasOwnProperty and can determine if the object has a property of any kind using
var hasProperty = (typeof obj[key] != 'undefined')
or the relatively more recent
var hasProperty = (obj[key] !== undefined)
I say relatively more recent because in some browsers the value of undefined could be set. (Note the strict inequality sign, because undefined==null, but undefined!==null).

Now that we went through methods of iterating over the elements of arrays, it's trivial to enumerate the HTML attributes of an element, because they are stored in an attributes NamedNodeMap, which even if it looks like an array, with a length property and numeric indexes, it is not. forEach doesn't work, for example.

for (var i=0; i<obj.attributes.length; i++) {
  var attr=obj.attributes[i];

Note that console.log(attr) will return a string like representation of the object because for some reason attributes have a valueOf overload that turns them into a string like key="value". You can also transform the NamedNodeMap into an array using Array.from (not in IE or Opera!) then use forEach, if that's your thing.

And below is the 2006 post... yuck!

I've always needed to read the attributes of objects in Javascript for my
custom controls. Imagine a tag like this:
<span id=test1 attribute1="value">
followed by a Javascript code like this:

There are two solutions for reading the attributes of an object:
1. for-in loop:
for (var name in test1) alert(name+':'+test1[name]);
2. use the attributes property (the W3C DOM way)
for (var c=0; c<test1.attributes.length; c++) {
var attr=test1.attributes[c];
Or, if you are fortunate enough to know the attribute name, you can use

How nice. Now the good part, these pieces of code work differently for IE
and non IE browsers. What a surprise.
- both loops show all the properties of an object, including methods,
attributes specified in JS code or in html tags. The functions specified in
a tag are returned as [object]s.
- also setAttribute and getAttribute work the same, returning object
properties or tag attributes
FireFox, Opera and Netscape:
- the for-in loop returns only the object properties and methods, NOT the
things defined in the HTML tag
- the attributes loop returns ONLY the tag attributes
- getAttribute will only return the tag attribute while setAttribute will
change only the attributes, not the object model
- in the case that a tag attribute is automatically transformed by the
browser in an object property (like an event onchange="test();")
obj.onchange will return a function object, while
obj.getAttribute('onchange') will return a string

Therefore the only way I found to loop through all the properties of both
html tag and DOM object is by using both loops. ex:
function PassAttr(elem1,elem2) {
for (var c=0; c<elem1.attributes.length; c++) {
var attr=elem1.attributes[c];
if (,5)=='list_')
for (name in elem1)
if (name.substring(0,5)=='list_')