Aufzählbarkeit und Zugehörigkeit von Eigenschaften

Aufzählbare Eigenschaften sind jene, deren internes Statusfeld enumerable gesetzt ist.

Alle aufzählbaren Eigenschaften eines Objektes sind mit for...in-Schleifen zu durchlaufen (sofern der Name der Eigenschaft kein Symbol ist), daher die Bezeichnung „aufzählbar“.
Neben for…in gibt es weitere Möglichkeiten, die Existenz einer Eigenschaft zu erkennen, Eigenschaften aufzuzählen oder abzurufen. Siehe dazu nachfolgende Tabellen.

Standardmäßig aufzählbar sind Eigenschaften, die durch einfache Zuweisung oder Initialisierung entstanden sind, nicht jedoch Eigenschaften, die durch Object.defineProperty oder ähnliche Mechanismen erzeugt wurden.

Die Zugehörigkeit einer Eigenschaft ergibt sich aus dem Ort seiner Definition; dies ist entweder das Objekt selbst oder einer seiner Prototypen. Eine Eigenschaft, die im Objekt definiert wurde, gehört zu diesem Objekt.

Aufzählbarkeit und Zugehörigkeit – Eingebaute Methoden zur Erkennung, zum Abruf und zur Aufzählung
Funktion Objekt Objekt und geerbt aus Prototypenkette nur geerbt aus Prototypenkette
Erkennung
aufzählbar nicht aufzählbar aufzählbar und nicht aufzählbar

propertyIsEnumerable

hasOwnProperty

hasOwnProperty – aufzählbare Eigenschaften mit propertyIsEnumerable entfernt

hasOwnProperty
aufzählbar nicht aufzählbar aufzählbar und nicht aufzählbar
nur mit eigenem Code möglich nur mit eigenem Code möglich in
nur mit eigenem Code möglich
Abruf
aufzählbar nicht aufzählbar aufzählbar und nicht aufzählbar

Object.keys

getOwnPropertyNames 

getOwnPropertySymbols

getOwnPropertyNames, getOwnPropertySymbols – aufzählbare Eigenschaften mit propertyIsEnumerable entfernt

getOwnPropertyNames

getOwnPropertySymbols

nur mit eigenem Code möglich nur mit eigenem Code möglich
Aufzählung
aufzählbar nicht aufzählbar aufzählbar und nicht aufzählbar

Object.keys

getOwnPropertyNames 

getOwnPropertySymbols

getOwnPropertyNames, getOwnPropertySymbols – aufzählbare Eigenschaften mit propertyIsEnumerable entfernt

getOwnPropertyNames

getOwnPropertySymbols

aufzählbar nicht aufzählbar aufzählbar und nicht aufzählbar

for..in

(ohne Symbole)

nur mit eigenem Code möglich nur mit eigenem Code möglich
nur mit eigenem Code möglich

Sichtbarkeit von Eigenschaften

in for..in obj.hasOwnProperty obj.propertyIsEnumerable Object.keys Object.getOwnPropertyNames Object.getOwnPropertyDescriptors Reflect.ownKeys()
Aufzählbar ja ja ja ja ja ja ja ja
Nicht aufzählbar ja nein ja nein nein ja ja ja
Symbol als Name ja nein ja ja nein nein ja ja
Aufzählbar, geerbt ja ja nein nein nein nein nein nein
Nicht aufzählbar, geerbt ja nein nein nein nein nein nein nein
Symbol als Name, geerbt ja nein nein nein nein nein nein nein

Eigenschaften nach Aufzählbarkeit oder Zugehörigkeit abrufen

Der nachfolgende Code ist nicht immer der effizienteste Weg, aber als einfaches Beispiel gut geeignet.

  • Die Existenz einer Eigenschaft erkennen: SimplePropertyRetriever.theGetMethodYouWant(obj).indexOf(prop) > -1
  • Alle Eigenschaften durchlaufen:
    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;
    }
};

Siehe auch