Подтвердить что ты не робот

В чем разница между Reflect.ownKeys(obj) и Object.keys(obj)?

Тестирование их в реальном простом случае дает такой же результат:

const obj = {a: 5, b: 5};
console.log(Reflect.ownKeys(obj));
console.log(Object.keys(obj));

// Result
['a', 'b']
['a', 'b']

Когда Reflect.ownKeys(obj) выводит вывод, отличный от Object.keys(obj)?

4b9b3361

Ответ 1

Object.keys() возвращает array строк, которые являются собственными перечисляемыми свойствами объекта.

Reflect.ownKeys(obj) возвращает эквивалент:

Object.getOwnPropertyNames(target).
                   concat(Object.getOwnPropertySymbols(target))

Метод Object.getOwnPropertyNames() возвращает массив всех свойств (enumerable или не), найденный непосредственно на данном объекте.

Метод Object.getOwnPropertySymbols() возвращает массив всех свойств symbol, найденных непосредственно на заданном объекте.

var testObject;
Object.defineProperty(testObject, 'myMethod', {
    value: function () {
        alert("Non enumerable property");
    },
    enumerable: false
});

//does not print myMethod since it is defined to be non-enumerable
console.log(Object.keys(testObject));   

//prints myMethod irrespective of it being enumerable or not.
console.log(Reflect.ownKeys(testObject)); 

Небольшой fiddle, чтобы продемонстрировать.

Ответ 2

Сначала пример (ES6Fiddle):

// getFoo is property which isn't enumerable
var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
my_obj.foo = 1;

console.log(Object.keys(my_obj)); // console ['foo']
console.log(Reflect.ownKeys(my_obj)); // console ['getFoo', 'foo']

Здесь Reflect.ownKeys() возвращает массив собственных ключей свойств целевого объекта. А именно, массив всех свойств (перечисляемых или нет), найденных непосредственно на данном объекте, соединенных с массивом всех свойств symbol, найденных непосредственно после данный объект.

Object.ownKeys() будет возвращать только перечисленные свойства.

Перечислимыми свойствами являются те, которые могут быть перечислены for... in loop, за исключением свойств, унаследованных через цепочку прототипов. Подробнее см. описание MDN.

Резюме:

Reflect.ownKeys() является эквивалентом Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)), который возвращает как перечислимые, так и неперечислимые свойства

тогда

Object.keys() возвращает перечислимые свойства, но не возвращает неперечислимые свойства (что является характеристикой Object.getOwnPropertyNames()).

Ответ 3

  • Object.keys возвращает только перечислимые строковые ключи; Reflect.ownKeys возвращает обе строки и символьные ключи независимо от их перечислимости. Оба действуют только на собственные свойства.
  • Object.keys возвращает пустой массив, если аргумент не является объектом, а не null или undefined (например, Object.keys(1)), тогда как Reflect.ownKeys выбрасывает TypeError.
  • Reflect.ownKeys был представлен с ES6 и не поддерживается в старых JavaScript-машинах.

Ответ 4

В дополнение к тому, что уже упоминалось в других ответах, Reflect.ownKeys также гарантируется спецификацией возврата ключей (и символов) в следующем порядке:

  • Целочисленные цифровые клавиши в порядке возрастания (0, 1, 2)
  • Строковые ключи, в том порядке, в котором они были вставлены в объект
  • Символьные клавиши

Этот порядок требуется внутренним методом [[OwnPropertyKeys]], который вызывается Reflect.ownKeys.

Напротив, Object.keys вызывает EnumerableOwnPropertyNames, что требует:

  1. Расположите элементы в properties так, чтобы они находились в том же относительном порядке, который будет создан итератором, который будет возвращен, если внутренний метод EnumerateObjectProperties был вызван с помощью O.

Где EnumerateObjectProperties явно не указывает какой-либо порядок, в котором возвращаются свойства:

Механика и порядок перечисления свойств не указаны

Таким образом, если вы хотите быть абсолютно уверены, что, перебирая свойства объекта, вы выполняете итерацию в порядке вставки нечисловых ключей, обязательно используйте Reflect.ownKeys (или Object.getOwnPropertyNames, который также вызывает [[OwnPropertyKeys]]).

(С учетом всего вышесказанного, хотя Object.keys, его варианты, циклы for..in и JSON.stringify все официально итерируются в неопределенном, зависящем от реализации порядке, среды, как правило, повторяются в том же прогнозируемом порядке, что и Reflect.ownKeys, к счастью)