What are the benefits of making properties non-enumerable?

荒凉一梦 提交于 2019-11-26 19:27:24

问题


Enumerability is one of the three attributes of a property: writability, enumerability, and configurability. My questions are:

  • What are the benefit of making properties non-enumerable in JavaScript? I know we are hiding the property by making them non-enumerable, but what are the benefit of property hiding?
  • Can we access non-enumerable properties? If yes, then what is the benefit of making them non-enumerable?
  • Are all predefined properties of Objects set as non-enumerable? Such as the case of Array's pop and push properties being non-enumerable?

回答1:


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().

MDN explains it well with 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. But that makes the property enumerable and messes up what is returned in loops/keys collection (without using .hasOwnProperty...which not everyone uses).

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.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. 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.

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. Another example is the length property, which is not enumerated over.

Here's an example in general: 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)." - from MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys




回答2:


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. The user fires up the Node interpreter and creates a new instance of it by calling the constructor:

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. 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] }



回答3:


  • By making the property non-enumerable you can still access it. But when you apply a for in loop on the object the non-enumerable property won't be iterated.
  • See first point
  • Inherited properties of built-in objects(like push, pop, toString...) are not enumerable

    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
    


来源:https://stackoverflow.com/questions/14984533/what-are-the-benefits-of-making-properties-non-enumerable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!