Quels sont les avantages de rendre les propriétés non énumérées?

L'énumération est l'un des trois attributs d'une propriété: l'écriture, l'énumération et la configurabilité. Mes questions sont les suivantes:

  • Quels sont les avantages de rendre les propriétés non énumérées en JavaScript? Je sais que nous cachons la propriété en les rendant non énumérés, mais quel est l'avantage de la propriété cachée?
  • Peut-on accéder à des propriétés non énumérées? Si oui, alors, quel est l'avantage de les rendre non énumérables?
  • Est-ce que toutes les propriétés prédéfinies des Objets sont définies comme non énumérées? Comme le cas des propriétés pop et push de Array ne sont pas énumérables?

Je pense que le principal avantage est de pouvoir contrôler ce qui apparaît lors de l'énumération des propriétés d'un objet, par exemple for in ou Object.keys() .

MDN explique bien avec Object.defineProperty : https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty

Donc, normalement, lorsque les gens veulent ajouter une méthode à Object , comme un polyfill pour une méthode non prise en charge dans les anciens navigateurs, ils modifient le .prototype . Mais cela rend la propriété énumérable et gâche ce qui est retourné dans la collection de boucles / clés ( sans utiliser .hasOwnProperty … que tout le monde n'utilise pas).

Donc, au lieu de quelque chose comme:

 Object.prototype.myMethod = function () { alert("Ahh"); }; 

Vous pouvez utiliser Object.defineProperty pour dire explicitement qu'il ne soit pas énumérable:

 Object.defineProperty(Object.prototype, 'myMethod', { value: function () { alert("Ahh"); }, enumerable: false }); 

De cette façon, par exemple lorsque vous utilisez for (var key in obj) , "myMethod" ne sera pas un élément énuméré, et vous ne devrez pas vous soucier d'utiliser .hasOwnProperty . Le principal problème est que certains navigateurs ne l'appuient pas bien sûr: http://kangax.github.com/es5-compat-table/ et que toutes les bibliothèques / code ne l'utilisent pas, donc vous ne pouvez toujours pas compter Sur les bibliothèques externes / code à utiliser correctement et tout le temps.

Vous pouvez accéder à une propriété non énumérable à tout moment que vous le souhaitez, il ne s'affichera plus lors de l'énumération des propriétés de l'objet – c'est le point principal.

Et je crois que toutes les propriétés "prédéfinies" des objets ne sont pas énumérées. Par cela, je ne veux dire que des propriétés natives, pas nécessairement héritées ou créées. Donc, avec votre exemple, pop et push ne seront pas énumérés, mais Array.prototype.indexOf sera s'il est créé sous forme de polyfill sur un ancien navigateur qui ne prend pas en charge cette méthode … ce qui évidemment peut être évité En utilisant Object.defineProperty comme mon exemple ci-dessus. Un autre exemple est la propriété length , qui n'est pas énumérée.

Voici un exemple en général: http://jsfiddle.net/aHJ3g/

L'utilisation et la définition de Object.keys est importante: "Renvoie un tableau des propriétés énumérables d'un objet donné, dans le même ordre que celui fourni par une boucle for-in (la différence étant qu'une boucle for-in énumère les propriétés dans le Chaîne prototype aussi). " – de MDN – https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys

Un autre avantage majeur que je le vois, c'est qu'il empêche les propriétés privées d'un objet de polluer l'espace de noms public.

Dites que vous avez créé et publié une puissante bibliothèque appelée Cosmos . L'utilisateur déclenche l'interpréteur Node et crée une nouvelle instance en appelant le constructeur:

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

Maintenant, l'utilisateur tape simplement le cosmos et appuyez sur Entrer pour voir l'API publique qu'il prend en charge. Lequel des deux souhaitez-vous que l'utilisateur voie?

 { name: 'my empire', grow: [Function: grow], addStar: [Function: addStar], beautify: [Function: beautify], implode: [Function: implode], destroy: [Function: destroy] } 

OU

 { _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] } 
  • En rendant la propriété non énumérable, vous pouvez toujours y accéder. Mais lorsque vous appliquez une boucle en ligne sur l'objet, la propriété non énumérable ne sera pas itérée.
  • Voir le premier point
  • Les propriétés héritées des objets intégrés (comme push, pop, toString …) ne sont pas énumérables

     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