Caractère énumérable des propriétés et rattachement

Les propriétés dites « énumérables » sont celles qui peuvent être parcourues dans une boucle for..in (sauf si le nom de la propriété est un symbole). Techniquement, les propriétés énumérables sont celles dont le marqueur [[Enumerable]] (interne au moteur) vaut true. Le rattachement (ou la propriété) d'une propriété est déterminé selon qu'une propriété est directement liée à un objet ou descend grâce à la chaîne de prototypes. Il est également possible de récupérer toutes les propriétés d'un objet. Il existe plusieurs façons, gérées nativement, qui permettent de détecter/itérer/énumérer/récupérer des propriétés. Le tableau ci-dessous a pour but de lister celles qui sont disponibles. Des exemples de codes sont listés ci-après pour illustrer comment récupérer les autres propriétés

Caractère énumérable et « propriété » d'une propriété - méthodes natives pour détecter, récupérer et itérer
Fonctionnalité Objet en propre L'objet, ainsi que sa chaîne de prototypes Uniquement la chaîne de prototypes
Détection
Énumérable Non-énumérable Énumérable et non-énumérable
propertyIsEnumerable hasOwnProperty et non propertyIsEnumerable hasOwnProperty
Fonctionnalité non disponible sans code supplémentaire. Fonctionnalité non disponible sans code supplémentaire.
Récupération
Énumérable Non-énumérable Énumérable et non-énumérable
Object.keys getOwnPropertyNames puis filtrer les propriétés qui ne passent pas le test propertyIsEnumerable getOwnPropertyNames
Fonctionnalité non disponible sans code supplémentaire. Fonctionnalité non disponible sans code supplémentaire.
Itération
Énumérable Non-énumérable Énumérable et non-énumérable
Itérer grâce à Object.keys Itérer grâce à getOwnPropertyNames puis filtrer les propriétés qui ne passent pas le test propertyIsEnumerable Itérer grâce à getOwnPropertyNames
Énumérable Non-énumérable Énumérable et non-énumérable
for..in Fonctionnalité non disponible sans code supplémentaire. Fonctionnalité non disponible sans code supplémentaire.
Fonctionnalité non disponible sans code supplémentaire.

Obtenir les propriétés selon leur énumérabilité/rattachement

Note : les algorithmes utilisés ici ne sont pas les plus efficaces mais permettent juste de démontrer ce qu'on peut faire.

  • Pour utiliser la détection : SimplePropertyRetriever.laMéthodeGetSouhaitée(obj).indexOf(prop) > -1
  • Pour itérer : SimplePropertyRetriever.laMéthodeGetSouhaitée(obj).forEach(function (value, prop) {}); (ou avec filter(), map(), etc.)
var SimplePropertyRetriever = {
    getOwnEnumerables: function (obj) {
        return this._getPropertyNames(obj, true, false, this._enumerable); 
        // On pourrait aussi utiliser for..in en filtrant sur hasOwnProperty ou juste : 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);
        // Ou juste : 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); 
        // Ou juste 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 privées statiques pour vérifier les propriétés
    _enumerable : function (obj, prop) {
        return obj.propertyIsEnumerable(prop);
    },
    _notEnumerable : function (obj, prop) {
        return !obj.propertyIsEnumerable(prop);
    },
    _enumerableAndNotEnumerable : function (obj, prop) {
        return true;
    },
    // Fragment de code inspiré de 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;
    }
};

Tableau sur la détection

  in for..in hasOwnProperty propertyIsEnumerable Object.keys Object.getOwnPropertyNames Object.getOwnPropertyDescriptors
Peut être énumérée true true true true true true true
Ne peut pas être énumérée true false true false false true true
Héritée, peut être énumérée true true false false false false false
Héritée, ne peut pas être énumérée true false false false false false false
Clé de symbole true false true true false false true

Voir aussi

Étiquettes et contributeurs liés au document

Étiquettes : 
 Contributeurs à cette page : SphinxKnight
 Dernière mise à jour par : SphinxKnight,