在JavaScript中,我们有几种方法可以获取对象的属性,具体取决于我们想要获得的内容。
1)Object.keys()
,它返回一个对象的所有自己的可枚举属性,一个ECMA5方法。
2)一个for...in
循环,它返回一个对象的所有可枚举属性,无论它们是自己的属性,还是从原型链继承。
3)Object.getOwnPropertyNames(obj)
返回对象的所有属性,可枚举与否。
我们也有hasOwnProperty(prop)
这样的方法让我们检查属性是继承还是实际属于该对象,propertyIsEnumerable(prop)
,顾名思义,让我们检查属性是否可枚举
使用所有这些选项,无法获得对象的不可枚举,非自己的属性,这就是我想要做的。有没有办法做到这一点?换句话说,我可以以某种方式获取继承的非可枚举属性的列表吗?
谢谢。
答案 0 :(得分:99)
由于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 / inherited .. 请确认..
function getAllPropertyNames( obj ) {
var props = [];
do {
props= props.concat(Object.getOwnPropertyNames( obj ));
} while ( obj = Object.getPrototypeOf( obj ) );
return props;
}
答案 1 :(得分:1)
要获取某些实例的所有继承属性或方法,您可以使用类似
的内容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(","));
答案 2 :(得分:1)
利用套装可以带来更清洁的解决方案,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);
}
答案 3 :(得分:1)
使用递归的更干净的解决方案:
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
等应用相同的模板。
答案 4 :(得分:0)
这是我在研究这个主题时提出的解决方案。要获取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);
}
答案 5 :(得分:0)
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);
答案 6 :(得分:0)
如果您尝试记录父对象ex的非可枚举属性。默认情况下,es6中类中定义的方法在原型上设置,但设置为不可枚举。
Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
答案 7 :(得分:0)
在ES6中直接进行迭代:
function getAllPropertyNames(obj) {
let result = new Set();
while (obj) {
Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
obj = Object.getPrototypeOf(obj);
}
return Array.from(result);
}
答案 8 :(得分:0)
根据我的个人喜好实现:)
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);
}