Enumerability and ownership of properties

Enumerable properties are those properties whose internal [[Enumerable]] flag is set to true, which is the default for properties created via simple assignment or via a property initializer (properties defined via Object.defineProperty and such default [[Enumerable]] to false). Enumerable properties show up in for...in loops unless the property's name is a Symbol. Ownership of properties is determined by whether the property belongs to the object directly and not to its prototype chain. Properties of an object can also be retrieved in total. There are a number of built-in means of detecting, iterating/enumerating, and retrieving object properties, with the chart showing which are available. Some sample code follows which demonstrates how to obtain the missing categories.

Property enumerability and ownership - built-in methods of detection, retrieval, and iteration
Functionality Own object Own object and its prototype chain Prototype chain only
Detection
Enumerable Nonenumerable Enumerable and Nonenumerable

propertyIsEnumerable

hasOwnProperty

hasOwnProperty  filtered to exclude enumerables using propertyIsEnumerable hasOwnProperty
Not available without extra code Not available without extra code
Retrieval
Enumerable Nonenumerable Enumerable and Nonenumerable

Object.keys

getOwnPropertyNames 

getOwnPropertyNames filtered to exclude enumerables using propertyIsEnumerable getOwnPropertyNames
Not available without extra code Not available without extra code
Iteratable
Enumerable Nonenumerable Enumerable and Nonenumerable

Object.keys

getOwnPropertyNames 

getOwnPropertyNames - filtered to exclude enumerables using propertyIsEnumerable getOwnPropertyNames
Enumerable Nonenumerable Enumerable and Nonenumerable
for..in Not available without extra code Not available without extra code
Not available without extra code

Obtaining properties by enumerability/ownership

Note that this is not the most efficient algorithm for all cases, but useful for a quick demonstration.

  • Detection can occur by SimplePropertyRetriever.theGetMethodYouWant(obj).indexOf(prop) > -1
  • Iteration can occur by SimplePropertyRetriever.theGetMethodYouWant(obj).forEach(function (value, prop) {}); (or use filter(), map(), etc.)
var SimplePropertyRetriever = {
    getOwnEnumerables: function(obj) {
        return this._getPropertyNames(obj, true, false, this._enumerable); 
         // Or could use for..in filtered with hasOwnProperty or just this: return Object.keys(obj);
    },
    getOwnNonenumerables: function(obj) {
        return this._getPropertyNames(obj, true, false, this._notEnumerable);
    },
    getOwnEnumerablesAndNonenumerables: function(obj) {
        return this._getPropertyNames(obj, true, false, this._enumerableAndNotEnumerable); 
        // Or just use: return Object.getOwnPropertyNames(obj);
    },
    getPrototypeEnumerables: function(obj) {
        return this._getPropertyNames(obj, false, true, this._enumerable);
    },
    getPrototypeNonenumerables: function(obj) {
        return this._getPropertyNames(obj, false, true, this._notEnumerable);
    },
    getPrototypeEnumerablesAndNonenumerables: function(obj) {
        return this._getPropertyNames(obj, false, true, this._enumerableAndNotEnumerable);
    },
    getOwnAndPrototypeEnumerables: function(obj) {
        return this._getPropertyNames(obj, true, true, this._enumerable); 
        // Or could use unfiltered for..in
    },
    getOwnAndPrototypeNonenumerables: function(obj) {
        return this._getPropertyNames(obj, true, true, this._notEnumerable);
    },
    getOwnAndPrototypeEnumerablesAndNonenumerables: function(obj) {
        return this._getPropertyNames(obj, true, true, this._enumerableAndNotEnumerable);
    },
    // Private static property checker callbacks
    _enumerable: function(obj, prop) {
        return obj.propertyIsEnumerable(prop);
    },
    _notEnumerable: function(obj, prop) {
        return !obj.propertyIsEnumerable(prop);
    },
    _enumerableAndNotEnumerable: function(obj, prop) {
        return true;
    },
    // Inspired by http://stackoverflow.com/a/8024294/271577
    _getPropertyNames: function getAllPropertyNames(obj, iterateSelfBool, iteratePrototypeBool, includePropCb) {
        var props = [];
        do {
            if (iterateSelfBool) {
                Object.getOwnPropertyNames(obj).forEach(function(prop) {
                    if (props.indexOf(prop) === -1 && includePropCb(obj, prop)) {
                        props.push(prop);
                    }
                });
            }
            if (!iteratePrototypeBool) {
                break;
            }
            iterateSelfBool = true;
        } while (obj = Object.getPrototypeOf(obj));
        return props;
    }
};

Detection Table

  in for..in obj.hasOwnProperty obj.propertyIsEnumerable Object.keys Object.getOwnPropertyNames Object.getOwnPropertyDescriptors Reflect.ownKeys()
Enumerable true true true true true true true true
Nonenumerable true false true false false true true true
Symbols keys true false true false false false true true
Inherited Enumerable true true false false false false false false
Inherited Nonenumerable true false false false false false false false
Inherited Symbols keys true false false false false false false false

See also

Document Tags and Contributors

Tags: 
 Last updated by: nmve,