Перелічуваність та належність властивостей

Перелічуваними називаються властивості, чий внутрішній прапор перелічуваності має значення true, що є значенням за замовчуванням для властивостей, створених простим присвоєнням або за допомогою ініціалізатора властивості (властивості, визначені за допомогою Object.defineProperty та подібного, за замовчуванням мають значення перелічуваності false). Перелічувані властивості з'являються у циклах for...in, якщо тільки ключ властивості не є символом. Належність властивостей визначається тим, чи належить властивість безпосередньо до об'єкта, а не до його ланцюга прототипів. Властивості об'єкта також можна отримати всі загалом. Існують численні вбудовані засоби виявлення, перебору/переліку та отримання властивостей об'єкта, а у таблиці нижче наведено, які з них є доступними. Далі наведено зразок коду, який демонструє, як отримати відсутні категорії.

Перелічуваність та належність властивостей - вбудовані методи виявлення, отримання та перебору
Функціональність Власний об'єкт Власний об'єкт та його ланцюг прототипів Лише ланцюг прототипів
Виявлення
Перелічувані Неперелічувані Перелічувані та неперелічувані

propertyIsEnumerable

hasOwnProperty

hasOwnProperty – відфільтровані для виключення перелічуваних властивостей за допомогою propertyIsEnumerable

hasOwnProperty
Перелічувані Неперелічувані Перелічувані та неперелічувані
Недоступні без додаткового коду Недоступні без додаткового коду in
Недоступні без додаткового коду
Отримання
Перелічувані Неперелічувані Перелічувані та неперелічувані

Object.keys

getOwnPropertyNames 

getOwnPropertySymbols

getOwnPropertyNames, getOwnPropertySymbols – відфільтровані для виключення перелічуваних властивостей за допомогою propertyIsEnumerable

getOwnPropertyNames

getOwnPropertySymbols

Недоступні без додаткового коду Недоступні без додаткового коду
Перебір
Перелічувані Неперелічувані Перелічувані та неперелічувані

Object.keys

getOwnPropertyNames 

getOwnPropertySymbols

getOwnPropertyNames, getOwnPropertySymbols – відфільтровані для виключення перелічуваних властивостей за допомогою propertyIsEnumerable

getOwnPropertyNames

getOwnPropertySymbols

Перелічувані Неперелічувані Перелічувані та неперелічувані

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);
         // Або скористайтесь 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);
    },
    // Приватні статичні фукнції зворотного виклику для перевірки властивостей
    _enumerable: function(obj, prop) {
        return obj.propertyIsEnumerable(prop);
    },
    _notEnumerable: function(obj, prop) {
        return !obj.propertyIsEnumerable(prop);
    },
    _enumerableAndNotEnumerable: function(obj, prop) {
        return true;
    },
    // Натхненний http://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 obj.hasOwnProperty obj.propertyIsEnumerable Object.keys Object.getOwnPropertyNames Object.getOwnPropertyDescriptors Reflect.ownKeys()
Перелічувані true true true true true true true true
Неперелічувані true false true false false true true true
Символи true false true true false false true true
Успадковані перелічувані true true false false false false false false
Успадковані неперелічувані true false false false false false false false
Успадковані символи true false false false false false false false

Див. також