Что значит перечислимое?


151

Я был направлен в MDN для ... на странице, когда он сказал: "для ... итерации по перечисляемым свойствам объекта".

Затем я перешел на страницу « Перечислимость и владение свойствами», где говорилось: «Перечислимые свойства - это те, которые могут быть повторены циклом for..in».

Словарь определяет перечисляемое как исчисляемое, но я не могу реально представить, что это значит. Могу ли я получить пример чего-то перечисляемого?


Ты понимаешь что for-inзначит?

Из ответов я понял, что for..in позволяет всем перечисляемым свойствам объекта быть доступными для использования с оператором for
Патрик

6
Самое простое значение: будет ли свойство произведено for inциклом или нет (для тех, кто не хочет знать детали или просто не заботится;))
Томаш Рация

Ответы:


158

Перечислимое свойство - это свойство, которое может быть включено и посещено во время for..inциклов (или подобной итерации свойств, например Object.keys()).

Если свойство не идентифицируется как перечисляемое, цикл игнорирует то, что оно находится внутри объекта.

var obj = { key: 'val' };

console.log('toString' in obj); // true
console.log(typeof obj.toString); // "function"

for (var key in obj)
    console.log(key); // "key"

Свойство идентифицируется как перечисляемое или нет по собственному [[Enumerable]]атрибуту . Вы можете просмотреть это как часть дескриптора свойства :

var descriptor = Object.getOwnPropertyDescriptor({ bar: 1 }, 'bar');

console.log(descriptor.enumerable); // true
console.log(descriptor.value);      // 1

console.log(descriptor);
// { value: 1, writable: true, enumerable: true, configurable: true }

Затем for..inцикл перебирает имена свойств объекта.

var foo = { bar: 1, baz: 2};

for (var prop in foo)
    console.log(prop); // outputs 'bar' and 'baz'

Но, только оценивает его утверждение - console.log(prop);в этом случае - для тех свойств, [[Enumerable]]атрибут которых true.

Это условие выполняется, потому что у объектов гораздо больше свойств , особенно от наследования :

console.log(Object.getOwnPropertyNames(Object.prototype));
// ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", /* etc. */]

Каждое из этих свойств все еще существует в объекте :

console.log('constructor' in foo); // true
console.log('toString' in foo);    // true
// etc.

Но они пропускаются for..inциклом, потому что они не перечислимы.

var descriptor = Object.getOwnPropertyDescriptor(Object.prototype, 'constructor');

console.log(descriptor.enumerable); // false

Таким образом, свойство конструктора не перечисляемо, потому что оно не отображается в цикле for..in. Хотя имена свойств, таких как bar или baz, являются перечисляемыми, потому что вы смогли console.log каждое из объекта?
Патрик

5
Это не совсем правильно But, they are skipped (or not counted) by the for..in loop because they are not enumerable. Свойства on Object.prototypeфактически игнорируются, потому что они находятся дальше по цепочке прототипов, а не потому, что они не перечисляются. Ни getOwnPropertyNames()или keys()не показывают свойства, которые не являются объектом собственными. В качестве примечания следует отметить, что многие встроенные свойства не перечисляются и, следовательно, не будут отображаться с помощью keys(), но вам придется написать дополнительный код, если вы хотите обойти цепочку прототипов.
Магнус

буквально, перечислимый означает счетный
Кристиан Мэтью

49

Если вы создаете объект через myObj = {foo: 'bar'}или что-то около этого, все свойства перечисляются. Итак, более простой вопрос: что не перечислимо? Некоторые объекты имеют некоторые не перечисляемые свойства, например, если вы вызываете Object.getOwnPropertyNames([])(который возвращает массив всех свойств, перечислимых или нет, для []), он возвращает ['length'], который включает в себя не перечислимое свойство массива 'length' ,

Вы можете создать свои собственные не перечисляемые свойства, вызвав Object.defineProperty:

var person = { age: 18 };
Object.defineProperty(person, 'name', { value: 'Joshua', enumerable: false });

person.name; // 'Joshua'
for (prop in person) {
  console.log(prop);
}; // 'age'

Этот пример в значительной степени заимствует из неперечислимых свойств в JavaScript , но показывает перечисляемый объект. Свойства могут быть или не быть записываемыми, настраиваемыми или перечисляемыми. Джон Резиг обсуждает это в рамках объектов и свойств ECMAScript 5 .

И есть вопрос переполнения стека о том, почему вы хотите сделать свойства не перечисляемыми .


Хм, как против, так и против. Конечно, если в этом ответе есть что-то, что стоит понизить, добавьте комментарий здесь.
Carpeliam

1
Другой ответ написал это: var o = {}; o ['foo'] = 0; // перечислимый, обычный Object.defineProperty (o, 'bar', {value: 1}); // неисчислимый, странный Почему явно добавить enumerable: false?
Патрик

5
@ Патрик, я включил его здесь частично, чтобы из примера было ясно, что это вариант, но в зависимости от вашей аудитории явное решение может быть твердым решением, просто так, чтобы оно было понятно всем, кто читает ваш код.
Carpeliam

@carpeliam Спасибо за это короткое и очень ясное объяснение, я не мог получить принятый ответ, пока я не прошел через ваш: D
sandeepKumar

37

Это намного скучнее, чем то, что нужно визуализировать.

Во всех свойствах буквально есть атрибут, называемый перечислимым. Когда установлено значение false, for..inметод пропускает это свойство, делая вид, что его не существует.

Существует множество свойств для объектов, для которых «enumerable» имеет значение false, например «valueOf» и «hasOwnProperty», поскольку предполагается, что вы не хотите, чтобы механизм JavaScript выполнял итерации по ним.

Вы можете создавать свои собственные не перечисляемые свойства, используя Object.definePropertyметод:

  var car = {
    make: 'Honda',
    model: 'Civic',
    year: '2008',
    condition: 'bad',
    mileage: 36000
  };

  Object.defineProperty(car, 'mySecretAboutTheCar', {
    value: 'cat pee in back seat',
    enumerable: false
  });

Теперь о том, что есть даже секрет об автомобиле, скрыто. Конечно, они могут получить доступ к собственности напрямую и получить ответ:

console.log(car.mySecretAboutTheCar); // prints 'cat pee in back seat'

Но они должны знать, что свойство существует в первую очередь, потому что, если они пытаются получить к нему доступ for..inили Object.keysоно останется полностью секретным:

console.log(Object.keys(car)); //prints ['make', 'model', 'year', 'condition', 'mileage']

Они должны были просто назвать это «forInAble».


5
Голосовали за эту последнюю строчку - я думаю, что если бы она действительно была вызвана forInAble, никто бы об этом не спрашивал. Который поднимает мой вопрос - почему бы вы (или почему вы должны) установить свойство не счётна? Свойство length массива довольно часто используется в качестве примера неперечислимого свойства, но почему вы не можете просто установить его в перечисляемое (не ограничение JavaScript, я имею в виду, почему оно было установлено как не перечисляемое в JavaScript в первое место)?
Крис

Чтобы прояснить мой вопрос, почему было решено, что следующее не подходит: make: Honda Model: Civic secret: Cat pee length: 12
Chris

Хм ... возможно, я нашел ответ на свой вопрос. В поиске Google "Что вы подразумеваете под перечисляемыми типами данных?" Перечисленные данные имеют конечный набор значений. Перечислимый тип данных состоит из значений, которые вы разрешаете для этого типа, или перечислимых значений. Для перечислимых типов на основе целых чисел каждое перечисляемое значение состоит из имени и базового числового значения. Так что, если я правильно понимаю, поскольку существует бесконечное число возможных длин, вам придется назначать бесконечное количество имен, одно имя на каждую длину. Это правильно?
Крис

Что ж, отвечая на ваш первый вопрос, установка неперечислимого свойства для объекта является немного хакерской, поскольку единственный способ узнать, что находится на этом объекте, это посмотреть на код и как на базу кода развивается это может быть похоронен. Так что, как правило, вы не хотели бы использовать его. Относительно '.length', которое дает количество символов в строке или элементах в массиве, это просто то, что мы бы не хотели включать, если бы использовали 'for ... in.' Не могу ответить, почему боги Js сделали это так обязательно. У них есть причины ( гм ) мнения за пределами нашего понимания.
Габриэль Кункель

... и я не думаю, что смогу ответить на ваш второй вопрос о перечислимых типах данных, хотя, похоже, я мог бы некоторое время жевать, если бы у меня было время. :-)
Габриэль Кункель

9

Если у вас возникают трудности с визуализацией "что значит быть перечисляемым?" почему бы не спросить себя, что значит быть неисчисляемым ?

Я думаю об этом немного как это, неисчислимое свойство существует, но частично скрыто ; это означает, что неисчислимый странный. Теперь вы можете представить перечисляемое как то, что осталось - более естественное свойство, с которым мы привыкли сталкиваться с тех пор, как обнаружили Объекты . Рассматривать

var o = {};
o['foo'] =  0;                               // enumerable, normal
Object.defineProperty(o, 'bar', {value: 1}); // nonenumerable, weird

Теперь представьте for..in, что это псевдокод

for property in o:
    if not property enumerable continue // skip non-enumerable, "bar"
    else do /* whatever */              // act upon enumerable, "foo"

где тело цикла, который вы набрали в JavaScript, находится вместо/* whatever */


8

Я напишу одну строку определения ENUMERABLE

Enumerable: Указывает, может ли свойство быть возвращено в цикле for / in.

var obj = {};
Object.defineProperties(obj, {
    set1: {enumerable: true},
    set2: {enumerable: false},
});
Object.keys(obj); // ["set1"]
Object.getOwnPropertyNames(obj); // ["set1", "set2"]

0

методы не перечисляются; вернее, встроенные методы не выполняются после поиска того, что перечислимое означает для сценария Java; он просто ссылается на атрибут свойства ... все созданные объекты в ecma3 являются перечисляемыми, и теперь ecma5 вы можете определить его ... вот и все ...: D lol, мне понадобилось немного, чтобы найти ответ; но я верю, что об этом говорилось в книге Дэвида Фланагана ... поэтому я предполагаю, что это означает "скрытый" или не "скрытый" в том смысле, что методы не отображаются в цикле for in и, следовательно, "скрыты"


0

Представьте себе тип данных enum, просто структуру объектов, которые соответствуют разным числам. Объявить что-либо как перечисляемое означает объявить, что оно соответствует определенному числу, что позволяет ему получить место в Словаре, который представляет счетные компоненты объекта. Проще говоря, сделать объект перечисляемым - это то же самое, что сказать компилятору: «Эй, это свойство имеет значение, я хочу увидеть это, когда проверю данные этого объекта».


0

Встроенные методы, которые наследуют объекты, не перечисляются, но свойства, которые ваш код добавляет к объектам, перечислимы, если явно не указано

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.