可枚举性是属性的三个属性之一:可写性,可枚举性和可配置性。我的问题是:
pop
和push
属性是不可枚举的?答案 0 :(得分:39)
我认为主要的好处是能够控制枚举对象属性时显示的内容,例如for in
或Object.keys()
。
MDN通过Object.defineProperty
:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty
通常,当人们想要向Object
添加方法时,例如旧浏览器不支持的某种方法的polyfill,他们会修改.prototype
。但这使得该属性可以枚举并且弄乱了循环/键集合中返回的内容(不使用.hasOwnProperty
... ...并非每个人都使用)。
所以不是像:
Object.prototype.myMethod = function () {
alert("Ahh");
};
你可以使用Object.defineProperty
明确说明它不可枚举:
Object.defineProperty(Object.prototype, 'myMethod', {
value: function () {
alert("Ahh");
},
enumerable: false
});
这样,例如,当您使用for (var key in obj)
时,“myMethod”将不是枚举的项目,您也不必担心使用.hasOwnProperty
。这个问题的主要问题是某些浏览器当然不支持它:http://kangax.github.com/es5-compat-table/并且并非所有库/代码都使用它,因此您不能总是依赖外部库/代码来正确使用它们时间。
您可以随时访问不可枚举的属性,在枚举对象的属性时不会显示 - 这是主要观点。
我相信对象的所有“预定义”属性都是不可枚举的。通过这个,我真的只是意味着本机属性,不一定是继承或创建的。因此,对于您的示例,pop
和push
将不进行枚举,但Array.prototype.indexOf
如果在旧浏览器上创建为polyfill,则会{不支持这种方法......当然,可以像上面的例子一样使用Object.defineProperty
来避免这种方法。另一个例子是length
属性,它没有枚举过。
以下是一般示例:http://jsfiddle.net/aHJ3g/
Object.keys
的使用和定义很重要:“返回给定对象自己的可枚举属性的数组,其顺序与for-in
循环提供的顺序相同(不同之处在于{ {1}}循环枚举原型链中的属性。)“ - 来自MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
答案 1 :(得分:12)
我认为另一个主要好处是它可以防止对象的私有属性污染公共命名空间。
假设您已创建并发布了一个名为Cosmos
的强大库。用户激活Node解释器并通过调用构造函数创建它的新实例:
var Cosmos = require('Cosmos');
var cosmos = new Cosmos('my empire');
现在用户只需键入cosmos
并按Enter即可查看它支持的公共API。您希望用户看到哪两个?
{ name: 'my empire',
grow: [Function: grow],
addStar: [Function: addStar],
beautify: [Function: beautify],
implode: [Function: implode],
destroy: [Function: destroy] }
OR
{ _age: 25000,
_size: 35000,
_destroyed: false,
name: 'my empire',
_numStars: 200,
_init: [Function: _init],
grow: [Function: grow],
_grow: [Function: _grow],
addStar: [Function: addStar],
_checkStatus: [Function: _checkStatus],
beautify: [Function: beautify],
implode: [Function: implode],
destroy: [Function: destroy] }
答案 2 :(得分:2)
内置对象的继承属性(如push,pop,toString ...)不可枚举
var o = {a:1, b:2, c:3} // a,b,c are enumerable properties
o.propertyIsEnumerable("toString") // returns false, because it is a inherited property
for(p in o) console.log(p); // this loop will print a,b and c but not toString or other inherited properies
答案 3 :(得分:1)
这是我要问自己一个非常好的问题。经过一番调查,我的结论是:您肯定不需要此功能。
对于那些不知道什么是不可枚举的财产的人,请查看以下链接:
这很奇怪,但是枚举所说的“不可枚举”属性实际上非常简单:
// start with some enumerable properties
const foo = {
a: 1,
b: "yes",
c: function () {}
}
// then add a couple of non-enumerable ones
Object.defineProperty(foo, "d", { value: "hiding here", isEnumerable: false });
Object.defineProperty(foo, "e", { value: 42, isEnumerable: false });
const enumerableProperties = Object.keys(foo).join(", ");
console.info("Enumerables: " + enumerableProperties);
// Enumerables: a, b, c
const ownPropertyNames = Object.getOwnPropertyNames(foo).join(", ");
console.info("Enumerating also the non-enumerables: " + ownPropertyNames);
// Enumerating also the non-enumerables: a, b, c, d, e
当他们说您无法枚举它们时,他们专门指的是Object.keys()
和for..in
循环以及它们仅返回可枚举属性的事实。 getOwnPropertyNames()
并非如此。
好吧,现在我们在同一页上:对我来说,它看起来像是一种晦涩的语言功能,它只会使我的代码更难以阅读和理解。我根本想不出它的真正合法用途。
两个现有的答案都涉及两个非常具体的情况:
当您不得不弄乱某些第三方对象的原型以添加某些polyfill方法而又不破坏现有代码的情况下,这很有用,因为在特定情况下代码不能使用{{1} }或hasOwnProperty()
。如果是这种情况,则您必须支持非常旧的代码(即不符合当今最佳实践的旧代码),并且我为您感到抱歉(尽管我知道今天仍有许多系统正在维护中)不幸地是这种情况);
当您正在开发公共库并且想要保持面向公众的对象整洁时,它很有用。这很具体,对不对?而且我也不想为此而用几个Object.keys()
来污染我的图书馆代码。而且,由于我们现在有了private fields,所以该答案很快就变得古老了。最后,答案还指出,它还可以保持公共名称空间的整洁,但这不是事实。名称空间受到对象本身的污染,而不是其属性的污染。
因此,除非您不幸不得不维护旧代码,否则请不要使用它。你不需要它,相信我。如果您发现自己在枚举对象时需要隐藏一些属性的情况,那么您肯定会对其建模错误。只需将这些属性放在单独的对象中即可。它们无意与您拥有的其他财产一起生活。这将使您的代码更加整洁和易于理解,这是编写代码时应该努力实现的最重要的事情。
Here's a more detailed article证实了当今不可枚举的属性不再扮演重要角色的观点。