Enumerability and ownership of properties

  • Revision slug: Enumerability_and_ownership_of_properties
  • Revision title: Enumerability and ownership of properties
  • Revision id: 320931
  • Created:
  • Creator: Brettz9
  • Is current revision? No
  • Comment

Revision Content

Enumerable properties are those which can be iterating by a for..in loop.

Ownership of properties is determiend 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
in and hasOwnProperty in and not propertyIsEnumerable hasOwnProperty
Not available Not available
Retrieval
Enumerable Nonenumerable Enumerable and Nonenumerable
Object.keys getOwnPropertyNames filtered to include properties when not passing propertyIsEnumerable getOwnPropertyNames
Not available Not available
Iteration
Enumerable Nonenumerable Enumerable and Nonenumerable
for..in filtered by hasOwnProperty Iterate over getOwnPropertyNames filtered to include properties when not passing propertyIsEnumerable Iterate over getOwnPropertyNames
Enumerable Nonenumerable Enumerable and Nonenumerable
for..in Not available Not available
Not available

   

Obtaining properties by enumerability/ownership

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

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 = [];

        while (obj) {
            if (iterateSelfBool) {
                Object.getOwnPropertyNames(obj).forEach(function (prop) {
                    if (props.indexOf(prop) === -1 && includePropCb(obj, prop)) {
                        props.push(prop);
                    }
                });
            }
            if (!iteratePrototypeBool) {
                break;
            }
            iterateSelfBool = true;
            obj = Object.getPrototypeOf(obj);
        };

        return props;
    }
};

See also

 

Revision Source

<p>Enumerable properties are those which can be iterating by a for..in loop.</p>
<p>Ownership of properties is determiend by whether the property belongs to the object directly and not to its prototype chain.</p>
<p>Properties of an object can also be retrieved in total.</p>
<p>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.</p>
<p>&nbsp;</p>
<table height="138" summary="Property enumerability and ownership - detection, retrieval, and iteration" width="598">
  <caption>
    Property enumerability and ownership - built-in methods of detection, retrieval, and iteration</caption>
  <tbody>
    <tr>
      <th>Functionality</th>
      <th>Own object</th>
      <th>Own object and its prototype chain</th>
      <th>Prototype chain only</th>
    </tr>
    <tr>
      <td>Detection</td>
      <td>
        <table summary="Enumerability">
          <thead>
            <tr>
              <th scope="col">Enumerable</th>
              <th scope="col">Nonenumerable</th>
              <th scope="col">Enumerable and Nonenumerable</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><a href="/en-US/docs/JavaScript/Reference/Operators/in" title="/en-US/docs/JavaScript/Reference/Operators/in">in</a> and <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty">hasOwnProperty</a></td>
              <td><a href="/en-US/docs/JavaScript/Reference/Operators/in" title="/en-US/docs/JavaScript/Reference/Operators/in">in</a> and not <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable">propertyIsEnumerable</a></td>
              <td><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty">hasOwnProperty</a></td>
            </tr>
          </tbody>
        </table>
      </td>
      <td>Not available</td>
      <td>Not available</td>
    </tr>
    <tr>
      <td>Retrieval</td>
      <td>
        <table summary="Enumerability">
          <thead>
            <tr>
              <th scope="col">Enumerable</th>
              <th scope="col">Nonenumerable</th>
              <th scope="col">Enumerable and Nonenumerable</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys">Object.keys</a></td>
              <td><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames">getOwnPropertyNames</a> filtered to include properties when not passing <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable">propertyIsEnumerable</a></td>
              <td><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames">getOwnPropertyNames</a></td>
            </tr>
          </tbody>
        </table>
      </td>
      <td>Not available</td>
      <td>Not available</td>
    </tr>
    <tr>
      <td>Iteration</td>
      <td>
        <table summary="Enumerability">
          <thead>
            <tr>
              <th scope="col">Enumerable</th>
              <th scope="col">Nonenumerable</th>
              <th scope="col">Enumerable and Nonenumerable</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><a href="/en-US/docs/JavaScript/Reference/Statements/for...in" title="/en-US/docs/JavaScript/Reference/Statements/for...in">for..in</a> filtered by <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty">hasOwnProperty</a></td>
              <td>Iterate over <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames">getOwnPropertyNames</a> filtered to include properties when not passing <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable">propertyIsEnumerable</a></td>
              <td>Iterate over <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames">getOwnPropertyNames</a></td>
            </tr>
          </tbody>
        </table>
      </td>
      <td>
        <table summary="Enumerability">
          <thead>
            <tr>
              <th scope="col">Enumerable</th>
              <th scope="col">Nonenumerable</th>
              <th scope="col">Enumerable and Nonenumerable</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><a href="/en-US/docs/JavaScript/Reference/Statements/for...in" title="/en-US/docs/JavaScript/Reference/Statements/for...in">for..in</a></td>
              <td>Not available</td>
              <td>Not available</td>
            </tr>
          </tbody>
        </table>
      </td>
      <td>Not available</td>
    </tr>
  </tbody>
</table>
<p>&nbsp;&nbsp;&nbsp;</p>
<h2 id="Obtaining_properties_by_enumerability.2Fownership">Obtaining properties by enumerability/ownership</h2>
<pre class="brush: js">
// Note that this is not the most efficient algorithm for all cases, but useful for a quick demonstration

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 = [];

        while (obj) {
            if (iterateSelfBool) {
                Object.getOwnPropertyNames(obj).forEach(function (prop) {
                    if (props.indexOf(prop) === -1 &amp;&amp; includePropCb(obj, prop)) {
                        props.push(prop);
                    }
                });
            }
            if (!iteratePrototypeBool) {
                break;
            }
            iterateSelfBool = true;
            obj = Object.getPrototypeOf(obj);
        };

        return props;
    }
};</pre>
<h2 id="See_also">See also</h2>
<ul>
  <li><a href="/en-US/docs/JavaScript/Reference/Operators/in" title="/en-US/docs/JavaScript/Reference/Operators/in">in</a></li>
  <li><a href="/en-US/docs/JavaScript/Reference/Statements/for...in" title="/en-US/docs/JavaScript/Reference/Statements/for...in">for..in</a></li>
  <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty">hasOwnProperty</a></li>
  <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable">propertyIsEnumerable</a></li>
  <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames">getOwnPropertyNames</a></li>
  <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys" title="/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys">Object.keys</a></li>
</ul>
<p>&nbsp;</p>
Revert to this revision