使属性不可枚举的好处是什么?
可枚举性是属性的三个属性之一:可写性,可枚举性和可configuration性。 我的问题是:
- 在JavaScript中使属性不可枚举有什么好处? 我知道我们是通过使它们不可枚举来隐藏财产,但财产隐藏的好处是什么?
- 我们可以访问非枚举属性吗? 如果是,那么使它们不可枚举的好处是什么?
- 对象的所有预定义属性都设置为不可枚举吗? 比如Array的
pop
和push
属性是不可枚举的?
我认为主要的好处是能够控制枚举对象的属性时显示的内容,例如for in
或Object.keys()
。
MDN用Object.defineProperty
解释了它: https : //developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty
所以通常情况下,当人们想要为Object
添加一个方法时,比如旧的浏览器中不支持的某种方法的.prototype
,他们会修改.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/并不是所有的库/代码都使用它,所以你不能总是依赖在外部库/代码做正确的使用和所有的时间。
你可以在任何时候访问一个不可枚举的属性,当枚举对象的属性时它不会显示出来 – 这就是要点。
而且我相信对象的所有“预定义”属性都是不可枚举的。 由此,我真的只是指本地属性,不一定是inheritance或创build。 因此,在你的例子中, pop
和push
不会被枚举,但是Array.prototype.indexOf
会被创build为一个不支持该方法的旧浏览器的polyfill,这当然是可以避免的通过使用Object.defineProperty
像我上面的例子。 另一个例子是length
属性,这是不枚举。
下面是一个例子: http : //jsfiddle.net/aHJ3g/
Object.keys
的使用和定义是很重要的:“返回一个给定对象自己可枚举属性的数组,其顺序与由for-in
循环提供的顺序相同(区别在于for-in
循环枚举了原型链也是如此)“。 – 来自MDN – https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
我看到的另一个主要好处是它可以防止对象的私有属性污染公共名称空间。
假设您已经创build并发布了一个名为Cosmos
的强大库。 用户启动Node解释器并通过调用构造函数来创build它的新实例:
var Cosmos = require('Cosmos'); var cosmos = new Cosmos('my empire');
现在,用户只需inputcosmos
然后按回车即可查看它支持的公共API。 你想让用户看到哪两个?
{ name: 'my empire', grow: [Function: grow], addStar: [Function: addStar], beautify: [Function: beautify], implode: [Function: implode], destroy: [Function: destroy] }
要么
{ _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] }
- 通过使属性不可枚举,你仍然可以访问它。 但是,当您在对象上应用for循环时,不可枚举属性将不会被迭代。
- 看第一点
-
内置对象(如push,pop,toString …)的inheritance属性是不可枚举的
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