web-dev-qa-db-fra.com

Est-il possible d'obtenir les noms de propriété hérités non énumérables d'un objet?

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.

87
dkugappi

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;
}
102
airportyh

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);
}
2
rich remer

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))];
}

Éditer

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.

1
Josh Klodnicki

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(","));
1
Milan Jaric

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));
0
Rahil Ahmad

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);
}
0
golem
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);
0
Dmitry Ragozin