51

可枚举性是属性的三个属性之一:可写性、可枚举性和可配置性。我的问题是:

  • 在 JavaScript 中使属性不可枚举有什么好处?我知道我们通过使它们不可枚举来隐藏属性,但是隐藏属性有什么好处?
  • 我们可以访问不可枚举的属性吗?如果是,那么使它们不可枚举有什么好处?
  • 对象的所有预定义属性是否都设置为不可枚举?例如数组poppush属性不可枚举的情况?
4

4 回答 4

42

我认为主要的好处是能够控制在枚举对象的属性时显示的内容,例如for inor Object.keys()

MDN 很好地解释了它Object.definePropertyhttps ://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty

所以通常,当人们想要Object.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/并不是所有的库/代码都使用它,所以你不能总是依赖在外部库/代码上始终正确使用。

您可以随时访问不可枚举的属性,它只是在枚举对象的属性时不会显示 - 这是重点。

而且我确实相信对象的所有“预定义”属性都是不可枚举的。我真的只指本机属性,不一定是继承或创建的。因此,对于您的示例,poppush不会枚举,但Array.prototype.indexOf如果它是在不支持该方法的旧浏览器上创建为 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

于 2013-02-20T16:20:00.773 回答
13

我认为的另一个主要好处是,它可以防止对象的私有属性污染公共命名空间。

假设您创建并发布了一个强大的库,名为Cosmos. 用户启动 Node 解释器并通过调用构造函数创建它的新实例:

var Cosmos = require('Cosmos');
var cosmos = new Cosmos('my empire');

现在用户只需键入cosmos并按下回车键即可查看它支持的公共 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] }
于 2013-07-28T07:22:44.067 回答
2

不可枚举的属性没有真正的实际用途

这是一个非常好的问题,我正要问自己。经过一番调查,我的结论是:你肯定不需要这个功能。

背景

对于那些不知道什么是不可枚举属性的人,请查看以下链接:

您实际上可以枚举它们

这很奇怪,但枚举所说的“不可枚举”属性实际上非常简单:

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

不要使用它

好的,现在我们在同一页上:在我看来,它就像一种晦涩难懂的语言功能,只会让我的代码更难阅读和理解。我根本想不出真正合法的用途。

现有的两个答案都讨论了两个非常具体的案例:

  1. 当您不得不弄乱某些第三方对象的原型以添加一些 polyfill 方法而不破坏现有代码的特定情况下代码不使用hasOwnProperty()or保护自己时,它很有用Object.keys()。如果这是您的情况,您将不得不支持非常旧的代码(即不符合当今最佳实践的遗留代码),我为您感到抱歉(尽管我知道今天仍有很多系统仍在维护不幸的是,属于这种情况);

  2. 当您开发公共库并希望保持面向公众的对象干净时,它很有用。这是非常具体的,对吧?而且我也不想defineProperty仅仅为此而用几个 s 污染我的图书馆的代码。此外,这个答案很快就会过时,因为我们现在有私有字段。最后,答案还表明它也会保持公共命名空间的清洁,但事实并非如此;命名空间被对象本身污染,而不是其属性。

因此,除非您不幸不得不维护旧代码,否则请忘记使用它。你不需要它,相信我。如果您发现自己在枚举对象时需要隐藏某些属性,那么您肯定是在建模错误。只需将这些属性放在单独的对象中即可。它们并不意味着与您拥有的其他财产一起生活。这将使您的代码更清晰,更易于理解,这是您在编写代码时应该努力实现的最重要的事情。

这是一篇更详细的文章,证实了不可枚举的属性如今已不起重要作用。

于 2019-12-15T13:17:22.990 回答
0
  • 通过使属性不可枚举,您仍然可以访问它。但是,当您在对象上应用 for in 循环时,将不会迭代不可枚举的属性。
  • 见第一点
  • 继承的属性是可枚举的(只要它们被标记为可枚举的)

    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);
    y.c = 3;
    for(p in y) console.log(p); // this loop will print c, a and b but not toString
    
于 2013-02-20T16:16:55.127 回答