【发布时间】:2014-05-04 16:58:17
【问题描述】:
javascript中Object.getOwnPropertyNames和Object.keys有什么区别?还有一些例子将不胜感激。
【问题讨论】:
-
从MDN上的文章来看,区别在于返回的列表是否包含不可枚举的属性:
Object.keys()不返回,Object.getOwnPropertyNames()有。
标签: javascript
javascript中Object.getOwnPropertyNames和Object.keys有什么区别?还有一些例子将不胜感激。
【问题讨论】:
Object.keys()不返回,Object.getOwnPropertyNames()有。
标签: javascript
如前所述,.keys 不会返回不可枚举的属性。
关于示例,其中一种陷阱情况是 Error 对象:它的某些属性是不可枚举的。
所以虽然console.log(Object.keys(new Error('some msg'))) 产生[],
console.log(Object.getOwnPropertyNames(new Error('some msg'))) 产生 ["stack", "message"]
console.log(Object.keys(new Error('some msg')));
console.log(Object.getOwnPropertyNames(new Error('some msg')));
【讨论】:
有一点不同。 Object.getOwnPropertyNames(a) 返回对象a 的所有属性。 Object.keys(a) 返回所有可枚举 自己的属性。这意味着如果你定义你的对象属性而不创建它们中的一些enumerable: false,这两种方法会给你同样的结果。
很容易测试:
var a = {};
Object.defineProperties(a, {
one: {enumerable: true, value: 1},
two: {enumerable: false, value: 2},
});
Object.keys(a); // ["one"]
Object.getOwnPropertyNames(a); // ["one", "two"]
如果你定义一个属性而不提供属性属性描述符(意味着你不使用Object.defineProperties),例如:
a.test = 21;
然后这样的属性会自动成为一个可枚举的并且两个方法都产生相同的数组。
【讨论】:
length属性是不可枚举的,所以它不会出现在Object.keys中。
length 属性位于原型上,而不是对象本身,因此Object.keys 和Object.getOwnPropertyNames 都不会列出它。
Object.getOwnPropertyNames(anyArray) 的结果包括 length
Object.getOwnPropertyNames(anyArray) 确实在返回的数组中包含 length!
创建对象时的文字符号与构造函数。 这让我很受启发。
const cat1 = {
eat() {},
sleep() {},
talk() {}
};
// here the methods will be part of the Cat Prototype
class Cat {
eat() {}
sleep() {}
talk() {}
}
const cat2 = new Cat()
Object.keys(cat1) // ["eat", "sleep", "talk"]
Object.keys(Object.getPrototypeOf(cat2)) // []
Object.getOwnPropertyNames(cat1) // ["eat", "sleep", "talk"]
Object.getOwnPropertyNames(Object.getPrototypeOf(cat2)) // ["eat", "sleep", "talk"]
cat1 // {eat: function, sleep: function, talk: function}
cat2 // Cat {}
// a partial of a function that is used to do some magic redeclaration of props
function foo(Obj) {
var propNames = Object.keys(Obj);
// I was missing this if
// if (propNames.length === 0) {
// propNames = Object.getOwnPropertyNames(Obj);
// }
for (var prop in propNames) {
var propName = propNames[prop];
APIObject[propName] = "reasign/redefine or sth";
}
}
所以在我的情况下,如果我给它提供 cat2 类型的对象,foo 函数就不起作用。
还有其他方法可以创建对象,因此其中也可能存在其他问题。
【讨论】:
Object.getOwnPropertyNames 将返回 cat1 而不是 cat2 的属性名称。两种创建对象的方式不会产生Object.getOwnPropertyNames 和Object.keys 之间的区别。
另一个区别是数组Object.getOwnPropertyNames 方法将返回一个额外的属性length。
var x = ["a", "b", "c", "d"];
Object.keys(x); //[ '0', '1', '2', '3' ]
Object.getOwnPropertyNames(x); //[ '0', '1', '2', '3', 'length' ]
【讨论】:
另一个区别是(至少在 nodejs 中)“getOwnPropertyNames”函数不保证键顺序,这就是我通常使用“keys”函数的原因:
Object.keys(o).forEach(function(k) {
if (!o.propertyIsEnumerable(k)) return;
// do something...
});
【讨论】:
getOwnPropertyNames 不正常的任何例子吗?因为 ES2015 指定了an order for Obect.getOwnPropertyNames,而order for Obect.keys 仍然由实现来决定。
for-in loop、Object.keys 和 Object.getOwnPropertyNames。也就是说,所有三个都将以一致的顺序相互枚举。