Javascript 是否可以获取对象的不可枚举继承属性名?
在JavaScript中,我们有几种获取对象属性的方法,具体取决于我们想要获取的内容 1)Javascript 是否可以获取对象的不可枚举继承属性名?,javascript,oop,object,properties,Javascript,Oop,Object,Properties,在JavaScript中,我们有几种获取对象属性的方法,具体取决于我们想要获取的内容 1) Object.keys(),它返回对象的所有自己的可枚举属性,即ECMA5方法 2) 一个for…in循环,返回对象的所有可枚举属性,无论它们是自己的属性还是从原型链继承的属性 function getAllProperties(obj){ var allProps = [] , curr = obj do{ var props = Object.getOwnP
Object.keys()
,它返回对象的所有自己的可枚举属性,即ECMA5方法
2) 一个for…in
循环,返回对象的所有可枚举属性,无论它们是自己的属性还是从原型链继承的属性
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
}
3) Object.getOwnPropertyNames(obj)
返回对象的所有自己的属性,无论是否可枚举
我们也有这样的方法,比如hasOwnProperty(prop)
让我们检查属性是继承的还是实际上属于该对象,以及propertyEnumerable(prop)
,顾名思义,它让我们检查属性是否可枚举
使用所有这些选项,无法获得对象的不可枚举、不可拥有的属性,这正是我想要做的。有没有办法做到这一点?换句话说,我能以某种方式获得继承的不可枚举属性的列表吗
谢谢。要获取某些实例的所有继承属性或方法,您可以使用如下内容
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(","));
由于
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__"]
更新:稍微重构了代码(添加了空格和大括号,并改进了函数名):
这是我在研究这个课题时提出的解决方案。获取
obj
对象dogetProperties(obj,“nonown”、“nonenum”)的所有不可枚举的非自有属性代码>
函数getProperties(对象、类型、可枚举性){
/**
*返回对象属性的数组
*@param{String}type-属性类型。可以是“own”、“nonown”或“两者”
*@param{String}可枚举性-属性可枚举性。可以是“enum”,
*“非数值”或“两者”
*@返回属性的{String | Array}数组
*/
var props=Object.create(null);//字典
var firstIteration=true;
做{
var allProps=Object.getOwnPropertyNames(obj);
var enumProps=Object.keys(obj);
var nonenumProps=allProps.filter(x=>!(新集合(enumProps)).has(x));
enumProps.forEach(函数(prop){
如果(!(道具中的道具)){
props[prop]={own:firstIteration,enum\uz:true};
}
});
非numprops.forEach(函数(prop){
如果(!(道具中的道具)){
props[prop]={own:firstIteration,enum_2;:false};
}
});
第一次迭代=假;
}while(obj=Object.getPrototypeOf(obj));
用于(道具中的道具){
if(type==“own”&&props[prop][“own”]==false){
删除道具[道具];
继续;
}
if(type==“nonown”&&props[prop][“own”]==true){
删除道具[道具];
继续;
}
if(可枚举性==“枚举”&&props[prop][“枚举”]==false){
删除道具[道具];
继续;
}
if(可枚举性==“非数值”&&props[prop][“枚举”]==true){
删除道具[道具];
}
}
返回对象。键(道具);
}
使用的示例:
function MakeA(){
}
var a = new MakeA();
var arNonEnumerable = getNonEnumerableNonOwnPropertyNames(a);
如果您试图记录父对象的不可枚举属性,例如,默认情况下,es6中类内定义的方法在prototype上设置,但设置为不可枚举
Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
IMO说,利用Sets可以得到一个更干净的解决方案
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);
}
使用递归的更干净的解决方案:
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
等应用相同的模板。在ES6中直接迭代:
function getAllPropertyNames(obj) {
let result = new Set();
while (obj) {
Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
obj = Object.getPrototypeOf(obj);
}
return [...result];
}
运行示例:
函数getAllPropertyNames(obj){
让结果=新集合();
while(obj){
Object.getOwnPropertyNames(obj.forEach)(p=>result.add(p));
obj=Object.getPrototypeOf(obj);
}
返回[…结果];
}
设obj={
abc:123,
xyz:1.234,
foobar:“你好”
};
log(getAllPropertyNames(obj))代码>我个人偏好中的一个实现:)
多亏了toby,我不明白的一点是:
while(curr=Object.getPrototypeOf(cure))
,因为条件语句使用赋值运算符而不是比较运算符,这不总是返回true吗?或者这一行实际上是在检查“curr”是否有原型?@AlexNabokov如果结果是falsy,它将返回false,这将在Object时发生。getPrototypeOf(cure)
在原型链的顶部返回null
。我猜这假设没有圆形原型链@AlexFunction.prototype
永远不能是“根”原型,因为它的prototype链接指向Object.prototype
。函数Object.getPrototypeOf(obj)
返回obj
原型链中最顶层的对象。它使您能够遵循obj
的原型链,直到到达其末端(null
值)。我不确定你的问题是什么…@Alex不,它不是未定义的Object.getPrototypeOf(John)
返回Boy.prototype
对象(正如它应该的那样)-请参见此处:。请注意,构造函数Boy
不在John
的原型链中。John
的原型链如下:Boy.prototype->Object.prototype->null
“我认为Object.getPrototypeOf(obj)将返回obj的构造函数的原型”-是。对于John
,他的构造函数是Boy
,而Boy
的prototype
属性是Boy.prototype
。所以Object.getPrototypeOf(John)
返回Boy.prototype
。您的问题回答了
function getAllPropertyNames(obj) {
let result = new Set();
while (obj) {
Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
obj = Object.getPrototypeOf(obj);
}
return [...result];
}
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);
}