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.
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 |
|
|
Cette fonctionnalité n'est pas disponible sans code supplémentaire. | ||||||||||||
Récupération |
|
Cette fonctionnalité n'est pas disponible sans code supplémentaire. | Cette fonctionnalité n'est pas disponible sans code supplémentaire. | ||||||||||||
Parcours |
|
|
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 utiliserfilter()
,map()
, etc.)
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 |