[英]What are the benefits of making properties non-enumerable?
Enumerability is one of the three attributes of a property: writability, enumerability, and configurability.可枚举性是属性的三个属性之一:可写性、可枚举性和可配置性。 My questions are:我的问题是:
pop
and push
properties being non-enumerable?例如 Array 的pop
和push
属性不可枚举的情况?I think the main benefit is to be able to control what shows up when enumerating an object's properties, such as for in
or Object.keys()
.我认为主要的好处是能够控制枚举对象属性时显示的内容,例如for in
或Object.keys()
。
MDN explains it well with Object.defineProperty
: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty MDN 用Object.defineProperty
很好地解释了它: https : //developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty
So normally, when people want to add a method to Object
, such as a polyfill for some method not supported in old browsers, they modify the .prototype
.所以通常,当人们想要向Object
添加一个方法时,例如为某些旧浏览器不支持的方法添加.prototype
,他们会修改.prototype
。 But that makes the property enumerable and messes up what is returned in loops/keys collection ( without using .hasOwnProperty
...which not everyone uses).但这使得属性可枚举并弄乱了循环/键集合中返回的内容(不使用.hasOwnProperty
...不是每个人都使用)。
So instead of something like:所以而不是像这样的东西:
Object.prototype.myMethod = function () {
alert("Ahh");
};
you could use Object.defineProperty
to explicitly say to have it not be enumerable:您可以使用Object.defineProperty
来明确表示它不可枚举:
Object.defineProperty(Object.prototype, 'myMethod', {
value: function () {
alert("Ahh");
},
enumerable: false
});
That way, for example when you use for (var key in obj)
, "myMethod" won't be an item enumerated, and you won't have to worry about using .hasOwnProperty
.这样,例如,当您使用for (var key in obj)
,“myMethod”将不会是一个枚举项,并且您不必担心使用.hasOwnProperty
。 The main problem with this is that some browsers don't support it of course: http://kangax.github.com/es5-compat-table/ and that not all libraries/code use it, so you can't always rely on external libraries/code to do use correctly and all the time.这样做的主要问题是一些浏览器当然不支持它: http : //kangax.github.com/es5-compat-table/并且不是所有的库/代码都使用它,所以你不能总是依赖在外部库/代码上始终正确使用。
You can access a non-enumerable property at any time you want, it just won't show up when enumerating the object's properties - that's the main point.您可以随时访问不可枚举的属性,它只是在枚举对象的属性时不会显示 - 这是重点。
And I do believe that all "predefined" properties of objects are non-enumerable.而且我确实相信对象的所有“预定义”属性都是不可枚举的。 By that, I really only mean native properties, not necessarily inherited or created.那个,我真的只是指原生属性,不一定是继承或创建的。 So with your example, pop
and push
will not be enumerated over, but Array.prototype.indexOf
will be if it is created as a polyfill on an old browser that doesn't support that method...which of course, can be avoided by using Object.defineProperty
like my example above.因此,对于您的示例,将不会枚举pop
和push
,但是如果在不支持该方法的旧浏览器上将其创建为 polyfill,则Array.prototype.indexOf
将是……这当然可以避免通过使用Object.defineProperty
就像我上面的例子一样。 Another example is the length
property, which is not enumerated over.另一个例子是length
属性,它没有被枚举。
Here's an example in general: http://jsfiddle.net/aHJ3g/这里有一个一般的例子: http : //jsfiddle.net/aHJ3g/
The use and definition of Object.keys
is important: "Returns an array of a given object's own enumerable properties, in the same order as that provided by a for-in
loop (the difference being that a for-in
loop enumerates properties in the prototype chain as well)." Object.keys
的使用和定义很重要:“返回给定对象自己的可枚举属性的数组,其顺序与for-in
循环提供的顺序相同(区别在于for-in
循环在原型链也是如此)。” - from MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys - 来自 MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
Another major benefit as I see it, is that it prevents private properties of an object from polluting the public namespace.在我看来,另一个主要好处是它可以防止对象的私有属性污染公共命名空间。
Say you have created and published a powerful library called Cosmos
.假设您创建并发布了一个名为Cosmos
的强大库。 The user fires up the Node interpreter and creates a new instance of it by calling the constructor:用户启动 Node 解释器并通过调用构造函数创建它的新实例:
var Cosmos = require('Cosmos');
var cosmos = new Cosmos('my empire');
Now the user simply types cosmos
and presses enter to see what public API it supports.现在,用户只需键入cosmos
并按 Enter 键即可查看它支持哪些公共 API。 Which of the two do you want the user to see?您希望用户看到这两个中的哪一个?
{ 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] }
This is a very nice question that I was about to ask myself.这是一个非常好的问题,我正要问自己。 After a bit of investigation, my conclusion is: you most certainly don't need this feature.经过一番调查,我的结论是:您肯定不需要此功能。
For those who don't know what a non-enumerable property is, take a look at the links below:对于那些不知道什么是不可枚举属性的人,请查看以下链接:
This is weird, but enumerating said "non-enumerable" properties is actually very simple:这很奇怪,但是枚举所说的“不可枚举”属性实际上非常简单:
// 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
When they say you can't enumerate them, they are referring specifically to Object.keys()
and the for..in
loop and the fact that they only return enumerable properties.当他们说你不能枚举它们时,他们特指的是Object.keys()
和for..in
循环以及它们只返回可枚举属性的事实。 That's not the case with getOwnPropertyNames()
. getOwnPropertyNames()
不是这种情况。
Ok, now that we are on the same page: it looks to me like an obscure language feature, one that would only make my code more difficult to read and understand.好的,现在我们在同一页面上:在我看来,它就像一种晦涩的语言功能,只会使我的代码更难以阅读和理解。 I simply can't think of a truly legitimate use for it.我简直想不出真正合法的用途。
Both existing answers talk about two very specific cases:现有的两个答案都讨论了两个非常具体的案例:
it is useful when you are having to mess with a prototype of some third-party object to add some polyfill method without breaking existing code in the specific case that the code doesn't protect itself using hasOwnProperty()
or Object.keys()
.当您不得不弄乱某些第三方对象的原型以添加一些 polyfill 方法而不破坏现有代码时,在代码不使用hasOwnProperty()
或Object.keys()
保护自己的特定情况下,它很有用。 If that's your case, you're having to support very old code (ie, legacy code that doesn't comply with today's best practices) and I feel sorry for you (although I know there are a lot of systems still being maintained today which fall into that case, unfortunately);如果这是您的情况,您将不得不支持非常旧的代码(即不符合当今最佳实践的遗留代码),我为您感到抱歉(尽管我知道今天仍有很多系统仍在维护中不幸的是,陷入这种情况);
it is useful for when you're developing a public library and want to keep your public-facing object clean.当您开发公共图书馆并希望保持面向公众的对象干净时,它很有用。 That is very specific, right?那很具体吧? And I also would prefer not to pollute my library's code with several defineProperty
s just for that.而且我也不想用几个defineProperty
来污染我图书馆的代码。 Moreover, that answer is quickly getting old because we now have private fields .此外,这个答案很快就会过时,因为我们现在有私有字段。 Finally, the answer also states that it would also keep the public namespace clean, but that's not true;最后,答案还指出它还会保持公共命名空间的清洁,但事实并非如此; the namespace is being polluted by the object itself, not its properties.命名空间被对象本身污染,而不是它的属性。
So, unless you're in unfortunate position of having to maintain old code, forget about using this.因此,除非您不幸不得不维护旧代码,否则请不要使用它。 You don't need it, trust me.你不需要它,相信我。 If you find yourself in the situation that you need to hide some properties when enumerating an object, you are certainly modeling it wrong.如果您发现自己在枚举对象时需要隐藏某些属性,那么您肯定是建模错误。 Just put those properties in a separate object.只需将这些属性放在一个单独的对象中。 They are not meant to live together with the other properties you have.它们并不意味着与您拥有的其他房产一起生活。 This will keep you code cleaner and easier to understand, which is the single most important thing you should strive to achieve when writing code.这将使您的代码更清晰、更易于理解,这是您在编写代码时应该努力实现的最重要的事情。
Here's a more detailed article corroborating the idea that non-enumerable properties play no significant role nowadays.这是一篇更详细的文章,证实了不可枚举属性在当今没有重要作用的观点。
Inherited properties are enumerable (as long as they are marked enumerable)继承的属性是可枚举的(只要它们被标记为可枚举)
var x = {a:1, b:2} // a and b are enumerable properties by default x.propertyIsEnumerable("toString") // returns false, because it is not marked as enumerable var y = Object.create(x); yc = 3; for(p in y) console.log(p); // this loop will print c, a and b but not toString
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.