Перелічуваними називаються властивості, чий внутрішній прапор перелічуваності має значення true, що є значенням за замовчуванням для властивостей, створених простим присвоєнням або за допомогою ініціалізатора властивості (властивості, визначені за допомогою Object.defineProperty та подібного, за замовчуванням мають значення перелічуваності false). Перелічувані властивості з'являються у циклах for...in, якщо тільки ключ властивості не є символом. Належність властивостей визначається тим, чи належить властивість безпосередньо до об'єкта, а не до його ланцюга прототипів. Властивості об'єкта також можна отримати всі загалом. Існують численні вбудовані засоби виявлення, перебору/переліку та отримання властивостей об'єкта, а у таблиці нижче наведено, які з них є доступними. Далі наведено зразок коду, який демонструє, як отримати відсутні категорії.
Перелічуваність та належність властивостей - вбудовані методи виявлення, отримання та перебору
Функціональність |
Власний об'єкт |
Власний об'єкт та його ланцюг прототипів |
Лише ланцюг прототипів |
Виявлення |
|
Перелічувані |
Неперелічувані |
Перелічувані та неперелічувані |
Недоступні без додаткового коду |
Недоступні без додаткового коду |
in |
|
Недоступні без додаткового коду |
Отримання |
|
Недоступні без додаткового коду |
Недоступні без додаткового коду |
Перебір |
|
Перелічувані |
Неперелічувані |
Перелічувані та неперелічувані |
for..in
(за винятком символів)
|
Недоступні без додаткового коду |
Недоступні без додаткового коду |
|
Недоступні без додаткового коду |
Зауважте, що це не найефективніший алгоритм для усіх випадків, але він корисний для швидкої демонстрації.
- Виявлення може відбуватись через
SimplePropertyRetriever.методЯкийВамПотрібен(obj).indexOf(prop) > -1
- Перебір може відбуватись через
SimplePropertyRetriever.методЯкийВамПотрібен(obj).forEach(function (value, prop) {});
(або скористайтесь filter()
, map()
і т. д.)
var SimplePropertyRetriever = {
getOwnEnumerables: function(obj) {
return this._getPropertyNames(obj, true, false, this._enumerable);
},
getOwnNonenumerables: function(obj) {
return this._getPropertyNames(obj, true, false, this._notEnumerable);
},
getOwnEnumerablesAndNonenumerables: function(obj) {
return this._getPropertyNames(obj, true, false, this._enumerableAndNotEnumerable);
},
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);
},
getOwnAndPrototypeNonenumerables: function(obj) {
return this._getPropertyNames(obj, true, true, this._notEnumerable);
},
getOwnAndPrototypeEnumerablesAndNonenumerables: function(obj) {
return this._getPropertyNames(obj, true, true, this._enumerableAndNotEnumerable);
},
_enumerable: function(obj, prop) {
return obj.propertyIsEnumerable(prop);
},
_notEnumerable: function(obj, prop) {
return !obj.propertyIsEnumerable(prop);
},
_enumerableAndNotEnumerable: function(obj, prop) {
return true;
},
_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;
}
};