Enumerable properties are those which can be iterated by a for..in loop.
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.
Functionality | Own object | Own object and its prototype chain | Prototype chain only | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Detection |
|
Not available without extra code | Not available without extra code | ||||||||||||
Retrieval |
|
Not available without extra code | Not available without extra code | ||||||||||||
Iteration |
|
|
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 https://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 | hasOwnProperty | propertyIsEnumerable | in Object.keys | in Object.getOwnPropertyNames | |
---|---|---|---|---|---|---|
Enumerable | true | true | true | true | true | true |
Nonenumerable | true | false | true | false | false | true |
Inherited Enumerable | true | true | false | false | false | false |
Inherited Nonenumerable | true | false | false | false | false | false |
See also