Rattachement et caractère énumérable des propriétés

Les propriétés dites « énumérables » sont celles pour lesquelles la caractéristique interne [[Enumerable]] vaut true. C'est le cas par défaut pour les propriétés qui sont créées grâce à une affectation simple ou grâce à un initialisateur de propriété. Les propriétés définies avec des méthodes analogues à Object.defineProperty() auront [[Enumerable]] à false). Les propriétés énumérables sont celles qui seront parcourues dans une boucle for..in (sauf si le nom de la propriété est un Symbol).

Le rattachement des propriétés est détérminé selon que la propriété est directement rattachée à l'objet et non à sa chaîne de prototypes. Il est également possible de récupérer l'ensemble des propriétés d'un objet. Dans le tableau suivant, on détaille les moyens possibles pour détecter, parcourir, énumérer, récupérer les propriétés d'un objet.

Caractère énumérable et rattachement - méthodes natives pour détecter, récupérer et parcourir les propriétés
Fonctionnalité Rattachement direct à l'objet Rattachement direct à l'objet et sur la chaîne de prototypes Uniquement sur la chaîne de prototypes
Détection
Énumérables Non-énumérables Toutes

propertyIsEnumerable()

hasOwnProperty()

hasOwnProperty() - en utilisant propertyIsEnumerable() afin d'exclure les propriétés énumérables hasOwnProperty()
Énumerables Non-énumérables Toutes
Cette fonctionnalité n'est pas disponible sans code supplémentaire. Cette fonctionnalité n'est pas disponible sans code supplémentaire. in
Cette fonctionnalité n'est pas disponible sans code supplémentaire.
Récupération
Énumérables Non-énumérables Toutes

Object.keys()

getOwnPropertyNames()

getOwnPropertySymbols()

getOwnPropertyNames() - getOwnPropertySymbols() en utilisant propertyIsEnumerable() afin d'exclure les propriétés énumérables

getOwnPropertyNames()

getOwnPropertySymbols()

Cette fonctionnalité n'est pas disponible sans code supplémentaire. Cette fonctionnalité n'est pas disponible sans code supplémentaire.
Parcours
Énumérables Non-énumérables Toutes

Object.keys()

getOwnPropertyNames()

getOwnPropertySymbols()

getOwnPropertyNames() - getOwnPropertySymbols()en utilisant propertyIsEnumerable() afin d'exclure les propriétés énumérables

getOwnPropertyNames()

getOwnPropertySymbols()

Énumerables Non-énumérables Toutes
for..in Cette fonctionnalité n'est pas disponible sans code supplémentaire. Cette fonctionnalité n'est pas disponible sans code supplémentaire.
Cette fonctionnalité n'est pas disponible sans code supplémentaire.

Obtenir les propriétés selon leur caractère énumérable et selon leur rattachement

Dans la plupart des cas, ce n'est pas l'algorithme le plus efficace mais il est présenté ici à des fins explicatives.

  • On peut détecter la présence d'une propriété grâce à RecuperateurDePropriete.laMethodeSouhaitee(obj).indexOf(prop) > -1
  • On peut parcourir les propriétés souhaitées avec RecuperateurDePropriete.laMethodeSouhaitee(obj).forEach(function (value, prop) {}); (on peut aussi utiliser filter(), map(), etc.)
js
var RecuperateurDePropriete = {
  getOwnEnumerables: function (obj) {
    return this._getPropertyNames(obj, true, false, this._enumerable);
    // On pourrait également utiliser for..in qu'on filtre avec hasOwnProperty
    // ou encore : 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,
    );
    // On peut également simplement utiliser : 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);
    // On pourra aussi utiliser for..in sans filtre
  },
  getOwnAndPrototypeNonenumerables: function (obj) {
    return this._getPropertyNames(obj, true, true, this._notEnumerable);
  },
  getOwnAndPrototypeEnumerablesAndNonenumerables: function (obj) {
    return this._getPropertyNames(
      obj,
      true,
      true,
      this._enumerableAndNotEnumerable,
    );
  },
  // Fonctions de rappels statiques
  _enumerable: function (obj, prop) {
    return obj.propertyIsEnumerable(prop);
  },
  _notEnumerable: function (obj, prop) {
    return !obj.propertyIsEnumerable(prop);
  },
  _enumerableAndNotEnumerable: function (obj, prop) {
    return true;
  },
  // Inspirée par 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;
  },
};

Tableau de détection

in for..in obj.hasOwnProperty() obj.propertyIsEnumerable() Object.keys() Object.getOwnPropertyNames() Object.getOwnPropertyDescriptors() Reflect.ownKeys()
Propriétés énumérables true true true true true true true true
Propriétés non-énumérables true false true false false true true true
Propriétés dont les clés sont des symboles true false true false false false true true
Propriétés héritées et énumérables true true false false false false false false
Propriétés héritées et non-énumérables true false false false false false false false
Propriétés héritées dont les clés sont des symboles true false false false false false false false

Voir aussi