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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8024149/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 02:01:11  来源:igfitidea点击:

Is it possible to get the non-enumerable inherited property names of an object?

javascriptoopobjectproperties

提问by dkugappi

In JavaScript we have a few ways of getting the properties of an object, depending on what we want to get.

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

1) Object.keys(), which returns all own, enumerable properties of an object, an ECMA5 method.

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

2) a for...inloop, which returns all the enumerable properties of an object, regardless of whether they are own properties, or inherited from the prototype chain.

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

3) Object.getOwnPropertyNames(obj)which returns all own properties of an object, enumerable or not.

3)Object.getOwnPropertyNames(obj)返回对象的所有属性,可枚举或不可枚举。

We also have such methods as hasOwnProperty(prop)lets us check if a property is inherited or actually belongs to that object, and propertyIsEnumerable(prop)which, as the name suggests, lets us check if a property is enumerable.

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

With all these options, there is no way to get a non-enumerable, non-ownproperty of an object, which is what I want to do. Is there any way to do this? In other words, can I somehow get a list of the inherited non-enumerable properties?

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

Thank you.

谢谢你。

回答by airportyh

Since getOwnPropertyNamescan get you non-enumerable properties, you can use that and combine it with walking up the prototype chain.

由于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
}

I tested that on Safari 5.1 and got

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


Update:Refactored the code a bit (added spaces, and curly braces, and improved the function name):

更新:稍微重构了代码(添加了空格和花括号,并改进了函数名称):

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

回答by Josh Klodnicki

A cleaner solution using recursion:

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

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

Edit

编辑

More generic functions:

更多通用功能:

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

This same template can be applied using Object.getOwnPropertySymbols, etc.

可以使用Object.getOwnPropertySymbols等来应用相同的模板。

回答by rich remer

Taking advantage of Sets leads to a somewhat cleaner solution, IMO.

利用 Sets 会带来更简洁的解决方案 IMO。

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

回答by nonopolarity

Straight forward iterative in ES6:

ES6 中的直接迭代:

function getAllPropertyNames(obj) {
    let result = new Set();
    while (obj) {
        Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
        obj = Object.getPrototypeOf(obj);
    }
    return [...result];
}

Example run:

示例运行:

function getAllPropertyNames(obj) {
  let result = new Set();
  while (obj) {
    Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
    obj = Object.getPrototypeOf(obj);
  }
  return [...result];
}

let obj = {
  abc: 123,
  xyz: 1.234,
  foobar: "hello"
};

console.log(getAllPropertyNames(obj));

回答by Milan Jaric

To get all inherited properties or methods for some instance you could use something like this

要获取某些实例的所有继承属性或方法,您可以使用这样的方法

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

回答by user3389370

An implementation in my personal preferences :)

我个人喜好的实现:)

function getAllProperties(In, Out = {}) {
    const keys = Object.getOwnPropertyNames(In);
    keys.forEach(key => Object.defineProperty(In, key, {
        enumerable: true
    }));
    Out = { ...In, ...Out };

    const Prototype = Object.getPrototypeOf(In);
    return Prototype === Object.prototype ? Out : getAllProperties(Proto, Out);
}

回答by golem

Here is the solution that I came up with while studying the subject. To get all non-enumerable non-own properties of the objobject do getProperties(obj, "nonown", "nonenum");

这是我在研究该主题时提出的解决方案。要获取对象的所有不可枚举的非拥有属性,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);
}

回答by Dmitry Ragozin

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

Example of using:

使用示例:

function MakeA(){

}

var a = new MakeA();

var arNonEnumerable = getNonEnumerableNonOwnPropertyNames(a);

回答by Rahil Ahmad

if you are trying to log non enumerable properties of a parent object ex. by default the methods defined inside a class in es6 are set on prototype but are set as non-enumerable.

如果您尝试记录父对象的不可枚举属性,例如。默认情况下,es6 中类中定义的方法设置在原型上,但设置为不可枚举。

Object.getOwnPropertyNames(Object.getPrototypeOf(obj));