是否可以获取对象的不可枚举继承属性名称?

2022-08-30 05:03:35

在JavaScript中,我们有几种方法可以获取对象的属性,具体取决于我们想要获得的内容。

1) ,返回对象的所有自己的可枚举属性,即 ECMA5 方法。Object.keys()

2) 一个循环,它返回对象的所有可枚举属性,无论它们是自己的属性,还是从原型链继承的。for...in

3) 返回对象的所有属性,无论是否可枚举。Object.getOwnPropertyNames(obj)

我们还有这样的方法,比如让我们检查一个属性是否是继承的,或者实际上属于该对象,顾名思义,它让我们检查一个属性是否是可枚举的。hasOwnProperty(prop)propertyIsEnumerable(prop)

使用所有这些选项,没有办法获得对象的不可枚举,非自己的属性,这是我想要做的。有什么办法可以做到这一点吗?换句话说,我能以某种方式获得继承的不可枚举属性的列表吗?

谢谢。


答案 1

由于可以获得不可枚举的属性,因此您可以使用它并将其与原型链相结合。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;
}

答案 2

使用递归的更简洁的解决方案:

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