En JavaScript, nous avons plusieurs façons d'obtenir les propriétés d'un objet, selon ce que nous voulons obtenir.
1) Object.keys()
, qui retourne toutes les propriétés énumérables d'un objet, une méthode ECMA5.
2) une boucle for...in
, Qui renvoie toutes les propriétés énumérables d'un objet, qu'elles soient propres ou héritées de la chaîne du prototype.
3) Object.getOwnPropertyNames(obj)
qui renvoie toutes les propriétés propres d'un objet, énumérables ou non.
Nous avons également des méthodes telles que hasOwnProperty(prop)
nous permet de vérifier si une propriété est héritée ou appartient réellement à cet objet, et propertyIsEnumerable(prop)
qui, comme son nom l'indique, nous permet de vérifier si une propriété est énumérable.
Avec toutes ces options, il n'y a aucun moyen d'obtenir une propriété non énumérable, non propre d'un objet, ce que je veux faire. Est-ce qu'il y a un moyen de faire ça? En d'autres termes, puis-je obtenir en quelque sorte une liste des propriétés non énumérables héritées?
Je vous remercie.
Puisque getOwnPropertyNames
peut vous obtenir des propriétés non énumérables, vous pouvez l'utiliser et la combiner avec la remontée de la chaîne de prototype.
function getAllProperties(obj){
var allProps = []
, curr = obj
do{
var props = Object.getOwnPropertyNames(curr)
props.forEach(function(prop){
if (allProps.indexOf(prop) === -1)
allProps.Push(prop)
})
}while(curr = Object.getPrototypeOf(curr))
return allProps
}
J'ai testé cela sur Safari 5.1 et j'ai
> getAllProperties([1,2,3])
["0", "1", "2", "length", "constructor", "Push", "slice", "indexOf", "sort", "splice", "concat", "pop", "unshift", "shift", "join", "toString", "forEach", "reduceRight", "toLocaleString", "some", "map", "lastIndexOf", "reduce", "filter", "reverse", "every", "hasOwnProperty", "isPrototypeOf", "valueOf", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "propertyIsEnumerable", "__lookupSetter__"]
pdate: Refactorisé un peu le code (ajout d'espaces et accolades et amélioration du nom de la fonction):
function getAllPropertyNames( obj ) {
var props = [];
do {
Object.getOwnPropertyNames( obj ).forEach(function ( prop ) {
if ( props.indexOf( prop ) === -1 ) {
props.Push( prop );
}
});
} while ( obj = Object.getPrototypeOf( obj ) );
return props;
}
Et pour obtenir tout simplement .. (enum/nonenum, self/inherited .. Veuillez confirmer ..
function getAllPropertyNames( obj ) {
var props = [];
do {
props= props.concat(Object.getOwnPropertyNames( obj ));
} while ( obj = Object.getPrototypeOf( obj ) );
return props;
}
Profiter de Sets conduit à une solution quelque peu plus propre, l'OMI.
const own = Object.getOwnPropertyNames;
const proto = Object.getPrototypeOf;
function getAllPropertyNames(obj) {
const props = new Set();
do own(obj).forEach(p => props.add(p)); while (obj = proto(obj));
return Array.from(props);
}
Une solution plus propre utilisant la récursivité:
function getAllPropertyNames (obj) {
const proto = Object.getPrototypeOf(obj);
const inherited = (proto) ? getAllPropertyNames(proto) : [];
return [...new Set(Object.getOwnPropertyNames(obj).concat(inherited))];
}
Fonctions plus génériques:
function walkProtoChain (obj, callback) {
const proto = Object.getPrototypeOf(obj);
const inherited = (proto) ? walkProtoChain(proto, callback) : [];
return [...new Set(callback(obj).concat(inherited))];
}
function getOwnNonEnumPropertyNames (obj) {
return Object.getOwnPropertyNames(obj)
.filter(p => !obj.propertyIsEnumerable(p));
}
function getAllPropertyNames (obj) {
return walkProtoChain(obj, Object.getOwnPropertyNames);
}
function getAllEnumPropertyNames (obj) {
return walkProtoChain(obj, Object.keys);
}
function getAllNonEnumPropertyNames (obj) {
return walkProtoChain(obj, getOwnNonEnumPropertyNames);
}
Ce même modèle peut être appliqué à l'aide de Object.getOwnPropertySymbols
, etc.
Pour obtenir toutes les propriétés ou méthodes héritées pour une instance, vous pouvez utiliser quelque chose comme ceci
var BaseType = function () {
this.baseAttribute = "base attribute";
this.baseMethod = function() {
return "base method";
};
};
var SomeType = function() {
BaseType();
this.someAttribute = "some attribute";
this.someMethod = function (){
return "some method";
};
};
SomeType.prototype = new BaseType();
SomeType.prototype.constructor = SomeType;
var instance = new SomeType();
Object.prototype.getInherited = function(){
var props = []
for (var name in this) {
if (!this.hasOwnProperty(name) && !(name == 'constructor' || name == 'getInherited')) {
props.Push(name);
}
}
return props;
};
alert(instance.getInherited().join(","));
si vous essayez de consigner les propriétés non énumérables d'un objet parent ex. par défaut, les méthodes définies dans une classe dans es6 sont définies sur prototype mais sont définies comme non énumérables.
Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
Voici la solution que j'ai trouvée en étudiant le sujet. Pour obtenir toutes les propriétés non propres non énumérables de l'objet obj
, faites getProperties(obj, "nonown", "nonenum");
function getProperties(obj, type, enumerability) {
/**
* Return array of object properties
* @param {String} type - Property type. Can be "own", "nonown" or "both"
* @param {String} enumerability - Property enumerability. Can be "enum",
* "nonenum" or "both"
* @returns {String|Array} Array of properties
*/
var props = Object.create(null); // Dictionary
var firstIteration = true;
do {
var allProps = Object.getOwnPropertyNames(obj);
var enumProps = Object.keys(obj);
var nonenumProps = allProps.filter(x => !(new Set(enumProps)).has(x));
enumProps.forEach(function(prop) {
if (!(prop in props)) {
props[prop] = { own: firstIteration, enum_: true };
}
});
nonenumProps.forEach(function(prop) {
if (!(prop in props)) {
props[prop] = { own: firstIteration, enum_: false };
}
});
firstIteration = false;
} while (obj = Object.getPrototypeOf(obj));
for (prop in props) {
if (type == "own" && props[prop]["own"] == false) {
delete props[prop];
continue;
}
if (type == "nonown" && props[prop]["own"] == true) {
delete props[prop];
continue;
}
if (enumerability == "enum" && props[prop]["enum_"] == false) {
delete props[prop];
continue;
}
if (enumerability == "nonenum" && props[prop]["enum_"] == true) {
delete props[prop];
}
}
return Object.keys(props);
}
function getNonEnumerableNonOwnPropertyNames( obj ) {
var oCurObjPrototype = Object.getPrototypeOf(obj);
var arReturn = [];
var arCurObjPropertyNames = [];
var arCurNonEnumerable = [];
while (oCurObjPrototype) {
arCurObjPropertyNames = Object.getOwnPropertyNames(oCurObjPrototype);
arCurNonEnumerable = arCurObjPropertyNames.filter(function(item, i, arr){
return !oCurObjPrototype.propertyIsEnumerable(item);
})
Array.prototype.Push.apply(arReturn,arCurNonEnumerable);
oCurObjPrototype = Object.getPrototypeOf(oCurObjPrototype);
}
return arReturn;
}
Exemple d'utilisation:
function MakeA(){
}
var a = new MakeA();
var arNonEnumerable = getNonEnumerableNonOwnPropertyNames(a);