Каковы преимущества того, чтобы свойства не перечислили?

Перечислимость - это один из трех атрибутов свойства: возможность записи, перечислимость и конфигурируемость. Мои вопросы:

  • В чем преимущество создания свойств, не перечислимых в JavaScript? Я знаю, что мы скрываем свойство, делая их неперечислимыми, но в чем преимущество скрытия собственности?
  • Можем ли мы получить доступ к неперечислимым свойствам? Если да, то в чем преимущество сделать их неперечислимыми?
  • Являются ли все предопределенные свойства объектов заданными как неперечислимые? Например, если свойства Array pop и push не перечислимы?

Ответ 1

Я думаю, что основное преимущество заключается в том, чтобы иметь возможность контролировать, что отображается при перечислении свойств объекта, таких как for in или Object.keys().

MDN хорошо объясняет это с помощью Object.defineProperty: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty

Так обычно, когда люди хотят добавить метод к Object, например, polyfill для некоторого метода, который не поддерживается в старых браузерах, они изменяют .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/ и что не все библиотеки/код используют его, поэтому вы не всегда можете полагаться на внешние библиотеки/код для правильного использования и все время.

Вы можете получить доступ к неперечислимому свойству в любое время, оно просто не появится при перечислении свойств объекта - это основная точка.

И я верю, что все "предопределенные" свойства объектов неперечислимы. Тем самым я действительно имею в виду только собственные свойства, не обязательно унаследованные или созданные. Итак, в вашем примере pop и push будут перечислены не, но 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

Ответ 2

Другим важным преимуществом, которое я вижу в нем, является то, что он предотвращает загрязнение публичного пространства имен частными свойствами объекта.

Предположим, вы создали и опубликовали мощную библиотеку под названием Cosmos. Пользователь запускает интерпретатор Node и создает новый экземпляр, вызывая конструктор:

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

Теперь пользователь просто набирает Cosmos и нажимает enter, чтобы узнать, какой публичный 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] }

Ответ 3

  • Предоставляя свойство неперечислимое, вы все равно можете его получить. Но когда вы применяете цикл for for для объекта, свойство non-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