loading...

JavaScript – Enumerating Properties

Instead of testing for the existence of individual properties,
we sometimes want to iterate through or obtain a list of all the
properties of an object. This is usually done with the for/in loop, although ECMAScript 5 provides
two handy alternatives.

The for/in loop was covered
in for/in. It runs the body of the loop once for
each enumerable property (own or inherited) of the specified object,
assigning the name of the property to the loop variable. Built-in
methods that objects inherit are not enumerable, but the properties that your
code adds to objects are enumerable (unless you use one of the
functions described later to make them nonenumerable). For example:

var o = {x:1, y:2, z:3};             // Three enumerable own properties
o.propertyIsEnumerable("toString")   // => false: not enumerable
for(p in o)                          // Loop through the properties
    console.log(p);                  // Prints x, y, and z, but not toString

Some utility libraries add new methods (or other properties) to
Object.prototype so that they are
inherited by, and available to, all objects. Prior to ECMAScript 5,
however, there is no way to make these added methods nonenumerable, so
they are enumerated by for/in
loops. To guard against this, you might want to filter the properties
returned by for/in. Here are two
ways you might do so:

for(p in o) {
    if (!o.hasOwnProperty(p)) continue;       // Skip inherited properties
}

for(p in o) {
    if (typeof o[p] === "function") continue; // Skip methods
}

Example 6-2 defines utility functions that use
for/in loops to manipulate object
properties in helpful ways. The extend() function, in particular, is one
that is commonly included in JavaScript utility libraries.[8]

Example 6-2. Object utility functions that enumerate properties

/*
 * Copy the enumerable properties of p to o, and return o.
 * If o and p have a property by the same name, o's property is overwritten.
 * This function does not handle getters and setters or copy attributes.
 */
function extend(o, p) {
    for(prop in p) {                         // For all props in p.
        o[prop] = p[prop];                   // Add the property to o.
    }
    return o;
}

/*
 * Copy the enumerable properties of p to o, and return o.
 * If o and p have a property by the same name, o's property is left alone.
 * This function does not handle getters and setters or copy attributes.
 */
function merge(o, p) {
    for(prop in p) {                           // For all props in p.
        if (o.hasOwnProperty[prop]) continue;  // Except those already in o.
        o[prop] = p[prop];                     // Add the property to o.
    }
    return o;
}

/*
 * Remove properties from o if there is not a property with the same name in p.
 * Return o.
 */
function restrict(o, p) {
    for(prop in o) {                         // For all props in o
        if (!(prop in p)) delete o[prop];    // Delete if not in p
    }
    return o;
}

/*
 * For each property of p, delete the property with the same name from o.
 * Return o.
 */
function subtract(o, p) {
    for(prop in p) {                         // For all props in p
        delete o[prop];                      // Delete from o (deleting a
                                             // nonexistent prop is harmless)
    }
    return o;
}

/*
 * Return a new object that holds the properties of both o and p.
 * If o and p have properties by the same name, the values from p are used.
 */
function union(o,p) { return extend(extend({},o), p); }

/*
 * Return a new object that holds only the properties of o that also appear
 * in p. This is something like the intersection of o and p, but the values of
 * the properties in p are discarded
 */
function intersection(o,p) { return restrict(extend({}, o), p); }

/*
 * Return an array that holds the names of the enumerable own properties of o.
 */
function keys(o) {
    if (typeof o !== "object") throw TypeError();  // Object argument required
    var result = [];                 // The array we will return
    for(var prop in o) {             // For all enumerable properties
        if (o.hasOwnProperty(prop))  // If it is an own property
            result.push(prop);       // add it to the array.
    }
    return result;                   // Return the array.
}

In addition to the for/in
loop, ECMAScript 5 defines two functions that enumerate property
names. The first is Object.keys(),
which returns an array of the names of the enumerable own properties
of an object. It works just like the keys() utility function shown in Example 6-2.

The second ECMAScript 5 property enumeration function is
Object.getOwnPropertyNames(). It
works like Object.keys() but
returns the names of all the own properties of the specified object,
not just the enumerable properties. There is no way to write this
function in ECMAScript 3, because ECMAScript 3 does not provide a way
to obtain the nonenumerable properties of an object.


[8] The implementation of extend() shown here is correct but does
not compensate for a well-known bug in Internet Explorer. We’ll
see a more robust version of extend() in Example 8-3.

Comments are closed.

loading...