使属性不可枚举有什么好处?

时间:2022-05-25 21:02:23

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?
  • 在JavaScript中使属性不可枚举有什么好处?我知道我们通过使它们不可枚举来隐藏财产,但财产隐藏的好处是什么?
  • 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?
  • 对象的所有预定义属性是否都设置为不可枚举?比如Array的pop和push属性是不可枚举的?

3 个解决方案

#1


37  

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

我认为主要的好处是能够控制枚举对象属性时出现的内容,例如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. But that makes the property enumerable and messes up what is returned in loops/keys collection (without using .hasOwnProperty...which not everyone uses).

通常,当人们想要向Object添加方法时,例如对于旧浏览器不支持的某种方法的polyfill,他们会修改.prototype。但是这使得属性可以枚举并且弄乱了循环/键集合中返回的内容(不使用.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. 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.

这样,例如当你使用for(obj中的var键)时,“myMethod”将不是枚举的项目,你不必担心使用.hasOwnProperty。这个问题的主要问题是某些浏览器当然不支持它: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. Another example is the length property, which is not enumerated over.

而且我确实认为对象的所有“预定义”属性都是不可枚举的。通过这个,我真的只是意味着本地属性,不一定是继承或创建的。因此,对于您的示例,不会枚举pop和push,但如果在不支持该方法的旧浏览器上将其创建为polyfill,则Array.prototype.indexOf将会被删除...当然,这可以避免通过使用Object.defineProperty,就像上面的例子一样。另一个例子是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)." - from MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys

Object.keys的使用和定义很重要:“返回给定对象自己的可枚举属性的数组,其顺序与for-in循环提供的顺序相同(不同之处在于for-in循环枚举了原型链也是如此。“ - 来自MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys

#2


12  

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:

假设您已经创建并发布了一个名为Cosmos的强大库。用户激活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. Which of the two do you want the user to see?

现在,用户只需键入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] }

#3


2  

  • 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.
  • 通过使属性不可枚举,您仍然可以访问它。但是当您在对象上应用for循环时,将不会迭代非可枚举属性。
  • See first point
  • 见第一点
  • Inherited properties of built-in objects(like push, pop, toString...) are not enumerable

    内置对象的继承属性(如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
    

#1


37  

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

我认为主要的好处是能够控制枚举对象属性时出现的内容,例如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. But that makes the property enumerable and messes up what is returned in loops/keys collection (without using .hasOwnProperty...which not everyone uses).

通常,当人们想要向Object添加方法时,例如对于旧浏览器不支持的某种方法的polyfill,他们会修改.prototype。但是这使得属性可以枚举并且弄乱了循环/键集合中返回的内容(不使用.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. 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.

这样,例如当你使用for(obj中的var键)时,“myMethod”将不是枚举的项目,你不必担心使用.hasOwnProperty。这个问题的主要问题是某些浏览器当然不支持它: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. Another example is the length property, which is not enumerated over.

而且我确实认为对象的所有“预定义”属性都是不可枚举的。通过这个,我真的只是意味着本地属性,不一定是继承或创建的。因此,对于您的示例,不会枚举pop和push,但如果在不支持该方法的旧浏览器上将其创建为polyfill,则Array.prototype.indexOf将会被删除...当然,这可以避免通过使用Object.defineProperty,就像上面的例子一样。另一个例子是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)." - from MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys

Object.keys的使用和定义很重要:“返回给定对象自己的可枚举属性的数组,其顺序与for-in循环提供的顺序相同(不同之处在于for-in循环枚举了原型链也是如此。“ - 来自MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys

#2


12  

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:

假设您已经创建并发布了一个名为Cosmos的强大库。用户激活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. Which of the two do you want the user to see?

现在,用户只需键入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] }

#3


2  

  • 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.
  • 通过使属性不可枚举,您仍然可以访问它。但是当您在对象上应用for循环时,将不会迭代非可枚举属性。
  • See first point
  • 见第一点
  • Inherited properties of built-in objects(like push, pop, toString...) are not enumerable

    内置对象的继承属性(如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