Можно ли получить не перечисляемые имена наследуемых свойств объекта? - PullRequest
86 голосов
/ 06 ноября 2011

В JavaScript у нас есть несколько способов получить свойства объекта, в зависимости от того, что мы хотим получить.

1) Object.keys(), который возвращает все собственные, перечисляемые свойства объекта, метод ECMA5.

2) цикл for...in, который возвращает все перечисляемые свойства объекта, независимо от того, являются ли они собственными свойствами или унаследованы от цепочки прототипов.

3) Object.getOwnPropertyNames(obj), которая возвращает все собственные свойства объекта, перечисляемые или нет.

У нас также есть такие методы, как hasOwnProperty(prop) позволяет нам проверить, является ли свойство унаследованным или действительно принадлежит этому объекту, и propertyIsEnumerable(prop), который, как следует из названия, позволяет нам проверить, является ли свойство перечисляемым.

Со всеми этими опциями нет способа получить не перечисляемое, не принадлежащее свойство объекта, что я и хочу сделать. Есть какой-либо способ сделать это? Другими словами, могу ли я как-то получить список унаследованных не перечисляемых свойств?

Спасибо.

Ответы [ 7 ]

101 голосов
/ 06 ноября 2011

Поскольку getOwnPropertyNames может дать вам неперечислимые свойства, вы можете использовать их и комбинировать с переходом по цепочке прототипов.

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
}

Я протестировал это на Safari 5.1 и получил

> 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__"]

Обновление: Немного переработан код (добавлены пробелы и фигурные скобки и улучшено имя функции):

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

И допросто получить все .. (enum / nonenum, self / наследуется .. Пожалуйста, подтвердите ..

function getAllPropertyNames( obj ) {
    var props = [];

    do {
        props= props.concat(Object.getOwnPropertyNames( obj ));
    } while ( obj = Object.getPrototypeOf( obj ) );

    return props;
}
2 голосов
/ 06 октября 2017

Использование комплектов приводит к несколько более чистому решению, ИМО.

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);
}
1 голос
/ 05 марта 2019

Чистое решение с использованием рекурсии:

function getAllPropertyNames (obj) {
    const proto     = Object.getPrototypeOf(obj);
    const inherited = (proto) ? getAllPropertyNames(proto) : [];
    return [...new Set(Object.getOwnPropertyNames(obj).concat(inherited))];
}

Редактировать

Более общие функции:

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

Этот же шаблон можно применить, используя Object.getOwnPropertySymbols и т. Д.

1 голос
/ 06 ноября 2011

Чтобы получить все унаследованные свойства или методы для некоторого экземпляра, вы можете использовать что-то вроде этого

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(","));
0 голосов
/ 20 июля 2017

, если вы пытаетесь зарегистрировать не перечисляемые свойства родительского объекта, напр.по умолчанию методы, определенные внутри класса в es6, устанавливаются для прототипа, но не перечисляются.

Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
0 голосов
/ 02 ноября 2016
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;
}

Пример использования:

function MakeA(){

}

var a = new MakeA();

var arNonEnumerable = getNonEnumerableNonOwnPropertyNames(a);
0 голосов
/ 17 января 2016

Вот решение, которое я придумала при изучении предмета.Чтобы получить все не перечисляемые несобственные свойства объекта obj, выполните 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...