В языке JavaScript свойства объектов могут быть перечисляемыми или неперечисляемыми (встречается вариант перевода: счётные или несчётные). Если внутреннему флагу [[Enumerable]] свойства присвоить значение true, то данное свойство становится перечисляемым. Это происходит по умолчанию для свойств, созданных простым присваиванием или через инициализацию свойств (свойства, определённые через Object.defineProperty получают по умолчанию значение флага [[Enumerable]] равным false). Перечисляемые свойства участвуют в итерации в цикле for...in, если только имя свойства не Символ. Принадлежность свойства определяется тем, принадлежит ли оно непосредственно объекту или получено из цепочки прототипов. Также можно получить весь список свойств объекта. Ниже, в таблице, указаны возможные способы нахождения, получения и итерации свойств объектов. Некоторые из них нельзя использовать без дополнительного кода, примеры которого приведены после таблицы.
Перечисляемость и принадлежность свойств - встроенные методы определения, получения и итерации
Назначение |
Свойства объекта |
Свойства объекта и его прототипов |
Свойства из цепочки прототипов |
Определение |
|
Недоступно без дополнительного кода |
Недоступно без дополнительного кода |
Получение |
|
Недоступно без дополнительного кода |
Недоступно без дополнительного кода |
Итерация |
|
Перечисляемые |
Неперечисляемые |
Перечисляемые и Неперечисляемые |
for..in |
Недоступно без дополнительного кода |
Недоступно без дополнительного кода |
|
Недоступно без дополнительного кода |
Доступ к свойствам по их перечисляемости/принадлежности
Хотим заметить, что данный алгоритм эффективен не для всех классов.
- Определение свойства:
SimplePropertyRetriever.theGetMethodYouWant(obj).indexOf(prop) > -1
- Итерация:
SimplePropertyRetriever.theGetMethodYouWant(obj).forEach(function (value, prop) {});
(or use filter()
, map()
, etc.)
var SimplePropertyRetriever = {
getOwnEnumerables: function (obj) {
return this._getPropertyNames(obj, true, false, this._enumerable);
// Или можно использовать for..in, отфильтрованный по hasOwnProperty или проще: return Object.keys(obj);
},
getOwnNonenumerables: function (obj) {
return this._getPropertyNames(obj, true, false, this._notEnumerable);
},
getOwnEnumerablesAndNonenumerables: function (obj) {
return this._getPropertyNames(obj, true, false, this._enumerableAndNotEnumerable);
// Или можно использовать: return Object.getOwnPropertyNames(obj);
},
getPrototypeEnumerables: function (obj) {
return this._getPropertyNames(obj, false, true, this._enumerable);
},
getPrototypeNonenumerables: function (obj) {
return this._getPropertyNames(obj, false, true, this._notEnumerable);
},
getPrototypeEnumerablesAndNonenumerables: function (obj) {
return this._getPropertyNames(obj, false, true, this._enumerableAndNotEnumerable);
},
getOwnAndPrototypeEnumerables: function (obj) {
return this._getPropertyNames(obj, true, true, this._enumerable);
// Или можно использовать for..in
},
getOwnAndPrototypeNonenumerables: function (obj) {
return this._getPropertyNames(obj, true, true, this._notEnumerable);
},
getOwnAndPrototypeEnumerablesAndNonenumerables: function (obj) {
return this._getPropertyNames(obj, true, true, this._enumerableAndNotEnumerable);
},
// Private static property checker callbacks
_enumerable : function (obj, prop) {
return obj.propertyIsEnumerable(prop);
},
_notEnumerable : function (obj, prop) {
return !obj.propertyIsEnumerable(prop);
},
_enumerableAndNotEnumerable : function (obj, prop) {
return true;
},
// По мотивам https://stackoverflow.com/a/8024294/271577
_getPropertyNames : function getAllPropertyNames(obj, iterateSelfBool, iteratePrototypeBool, includePropCb) {
var props = [];
do {
if (iterateSelfBool) {
Object.getOwnPropertyNames(obj).forEach(function (prop) {
if (props.indexOf(prop) === -1 && includePropCb(obj, prop)) {
props.push(prop);
}
});
}
if (!iteratePrototypeBool) {
break;
}
iterateSelfBool = true;
} while (obj = Object.getPrototypeOf(obj));
return props;
}
};
Определяемость свойств
|
in |
for..in |
hasOwnProperty |
propertyIsEnumerable |
in Object.keys |
in Object.getOwnPropertyNames |
Перечисляемые |
true |
true |
true |
true |
true |
true |
Неперечисляемые |
true |
false |
true |
false |
false |
true |
Унаследованные Перечисляемые |
true |
true |
false |
false |
false |
false |
Унаследованные Неперечисляемые |
true |
false |
false |
false |
false |
false |
Смотрите также