dku*_*ppi 90 javascript oop properties object
在JavaScript中,我们有几种获取对象属性的方法,具体取决于我们想要获得的内容.
1)Object.keys(),它返回一个对象的所有自己的可枚举属性,一个ECMA5方法.
2)一个for...in循环,它返回一个对象的所有可枚举属性,无论它们是自己的属性,还是从原型链继承.
3)Object.getOwnPropertyNames(obj)返回对象的所有属性,可枚举与否.
我们也有这样的方法hasOwnProperty(prop)让我们检查属性是继承还是实际属于该对象,propertyIsEnumerable(prop)顾名思义,它让我们检查属性是否可枚举.
有了所有这些选项,就无法获得对象的不可枚举的非自有属性,这就是我想要做的.有没有办法做到这一点?换句话说,我可以以某种方式获取继承的非可枚举属性的列表吗?
谢谢.
air*_*tyh 106
既然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
}
Run Code Online (Sandbox Code Playgroud)
我在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__"]
Run Code Online (Sandbox Code Playgroud)
更新:重新编写代码(添加空格和花括号,并改进了函数名称):
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;
}
Run Code Online (Sandbox Code Playgroud)
简单地得到一切......(enum/nonenum,self/inherited .. 请确认..
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
}
Run Code Online (Sandbox Code Playgroud)
Jos*_*cki 17
使用递归的更干净的解决方案:
function getAllPropertyNames (obj) {
const proto = Object.getPrototypeOf(obj);
const inherited = (proto) ? getAllPropertyNames(proto) : [];
return [...new Set(Object.getOwnPropertyNames(obj).concat(inherited))];
}
Run Code Online (Sandbox Code Playgroud)
更通用的功能:
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);
}
Run Code Online (Sandbox Code Playgroud)
可以使用Object.getOwnPropertySymbols等应用相同的模板。
Dav*_*idT 15
在看到Mozilla 的 JS 文档后特别指出:“没有单一机制可以迭代对象的所有属性;各种机制各自包含不同的属性子集。”...我确实有这个问题,尽管是较新的,因为我也想要符号键,并且我认为所有上面的答案早于这些)。
我来到这里希望其他人知道如何创建这样一个单一的机制。
此页面上没有一个答案似乎涵盖了所有内容,但在所有答案之间,我认为这是可以完成的 - 包括还排除烦人的顶级键的选项。
在探索Mozilla 的 JS 文档中的代码时, airportyh的答案启发了我,再加上同一页面上它下面的表格,我发现了新的Reflect.ownKeys. 这捕获了所有内容(包括符号)......除了继承的属性,但 airportyh 的答案遍历原型链解决了这个问题。
所以......结合所有这些发现并尽可能地简化,我想出了以下两个函数,(我相信)确实可以捕获所有内容。发布以防对其他人有帮助。
返回每个键,无论是否可枚举、字符串、符号、自己的、继承的和顶级。
function getAllKeys(obj) {
let keys = [];
// if primitive (primitives still have keys) skip the first iteration
if (!(obj instanceof Object)) {
obj = Object.getPrototypeOf(obj)
}
while (obj) {
keys = keys.concat(Reflect.ownKeys(obj));
obj = Object.getPrototypeOf(obj);
}
return keys;
}
Run Code Online (Sandbox Code Playgroud)
我真的很喜欢这种简单性,尽管我想知道我是否错过了什么。如果有人发现任何错误,请告诉我。
补充:
包括或排除:
(顺便说一句,我不是 JS 专家,所以也许我遗漏了一些东西。我有点困惑为什么这里没有其他人使用 Array.prototype.filter(),因为这不正是我们想要的吗?在做什么?)
我相信以下内容涵盖了它。默认情况下,除了顶级键之外的所有内容都包含在内。调整口味。如果这里有任何错误,我再次欢迎反馈:
function getAllKeysConditionally(obj, includeSelf = true, includePrototypeChain = true, includeTop = false, includeEnumerables = true, includeNonenumerables = true, includeStrings = true, includeSymbols = true) {
// Boolean (mini-)functions to determine any given key's eligibility:
const isEnumerable = (obj, key) => Object.propertyIsEnumerable.call(obj, key);
const isString = (key) => typeof key === 'string';
const isSymbol = (key) => typeof key === 'symbol';
const includeBasedOnEnumerability = (obj, key) => (includeEnumerables && isEnumerable(obj, key)) || (includeNonenumerables && !isEnumerable(obj, key));
const includeBasedOnKeyType = (key) => (includeStrings && isString(key)) || (includeSymbols && isSymbol(key));
const include = (obj, key) => includeBasedOnEnumerability(obj, key) && includeBasedOnKeyType(key);
const notYetRetrieved = (keys, key) => !keys.includes(key);
// filter function putting all the above together:
const filterFn = key => notYetRetrieved(keys, key) && include(obj, key);
// conditional chooses one of two functions to determine whether to exclude the top level or not:
const stopFn = includeTop ? (obj => obj === null) : (obj => Object.getPrototypeOf(obj) === null);
// and now the loop to collect and filter everything:
let keys = [];
while (!stopFn(obj, includeTop)) {
if (includeSelf) {
const ownKeys = Reflect.ownKeys(obj).filter(filterFn);
keys = keys.concat(ownKeys);
}
if (!includePrototypeChain) { break; }
else {
includeSelf = true;
obj = Object.getPrototypeOf(obj);
}
}
return keys;
}
Run Code Online (Sandbox Code Playgroud)
正如 Jeff Hykin 在评论中指出的,这些解决方案使用 Reflect ES6 中新增的箭头函数。因此至少需要 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];
}
Run Code Online (Sandbox Code Playgroud)
运行示例:
function getAllPropertyNames(obj) {
let result = new Set();
while (obj) {
Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
obj = Object.getPrototypeOf(obj);
}
return [...result];
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
15336 次 |
| 最近记录: |