5 минут, чтобы полностью понять Object.keys

внешний интерфейс Vue.js 360

Автор этой статьи:Berwin, Член рабочей группы Performance W3C, старший инженер-интерфейс 360 навигации. Ранний пользователь Vue.js, автор «Введение в Vue.js» (в публикации).Ссылка в блоге

На днях друг задал мне вопрос: почемуObject.keysВозвращаемое значение будет автоматически отсортировано?

Пример такой:

const obj = {
  100: '一百',
  2: '二',
  7: '七'
}
Object.keys(obj) // ["2", "7", "100"]

А следующий пример не сортирует автоматически?

const obj = {
  c: 'c',
  a: 'a',
  b: 'b'
}
Object.keys(obj) // ["c", "a", "b"]

Когда друг задал мне этот вопрос, я долго не мог на него ответить. Так что я проверилСпецификация ECMA262, и прочитав статью на этот счет, я понял, почему произошло такое странное.

Поэтому я написал эту статью, чтобы подробно представить, когдаObject.keysЧто происходит внутри, когда он вызывается.

1. Ответы

Подводя итог вышеизложенному вопросу,Object.keysВнутренне на основе имени свойстваkeyТипы выполняют различную логику сортировки. Есть три случая:

  1. Если тип имени свойстваNumber,ТакObject.keysВозвращаемое значение соответствуетkeyСортировать от меньшего к большему
  2. Если тип имени свойстваString,ТакObject.keysВозвращаемое значение сортируется в порядке возрастания по времени создания свойства.
  3. Если тип имени свойстваSymbol, то логичноStringтакой же

Это объясняет проблему выше.

Ниже мы подробно знакомимObject.keysКогда звонят, что происходит за кулисами.

2. КогдаObject.keysчто происходит за кулисами, когда это называется

когдаObject.keysфункция с параметрамиOПри вызове выполняются следующие действия:

Шаг 1: Преобразуйте параметры вObjectтип объекта.

Шаг 2: Получите список свойств через преобразованный объектproperties.

Примечание. Список свойствpropertiesимеет тип Список (Тип спискадаКанонический тип ECMAScript)

Шаг 3: Перечислите свойства типа спискаpropertiesПреобразуйте в массив, чтобы получить окончательный результат.

Спецификация определяет это так:

  1. передачаToObject(O)присвоить результат переменнойobj
  2. передачаEnumerableOwnPropertyNames(obj, "key")присвоить результат переменнойnameList
  3. передачаCreateArrayFromList(nameList)получить окончательный результат

2.1 Преобразование параметров в объект (ToObject(O))

ToObjectОперация изменяет параметры в соответствии с таблицей нижеOПреобразование в значение типа Object:

Тип параметра результат
Undefined выдает TypeError
Null выдает TypeError
Boolean возвращает новый логический объект
Number возвращает новый объект Number
String возвращает новый объект String
Symbol Возвращает новый объект Symbol
Object Возврат объекта напрямую

потому чтоObject.keysвнутриToObjectоперация, такObject.keysНа самом деле могут быть получены и другие типы параметров.

В приведенной выше таблице указано, как параметры различных типов будут преобразованы в тип объекта.

Мы можем просто написать несколько примеров, чтобы попробовать:

попробуй сначалаnullБудет ли он сообщать об ошибке:

Object.keys(null)фигура 1Object.keys(null)

Как показано на рисунке 1, действительно сообщается об ошибке.

Далее пробуем эффект чисел:

Object.keys(123)фигура 2Object.keys(123)

Как показано на рисунке 2, возвращается пустой массив.

Почему он возвращает пустой массив? См. рисунок 3:

new Number(123)изображение 3new Number(123)

Как показано на рис. 3, возвращаемый объект не имеет каких-либо извлекаемых свойств, поэтому возвращение пустого массива также является нормальным явлением.

Затем мы снова пробуем эффект String:

Object.keys('我是Berwin')Рисунок 4Object.keys('我是Berwin')

На рис. 4 мы увидим, что возвращаются некоторые числа строкового типа, поскольку объект String имеет извлекаемые свойства, см. рис. 5:

new String('我是Berwin')Рисунок 5new String('我是Berwin')

Поскольку объект String имеет извлекаемые свойства, имена свойств объекта String извлекаются и возвращаются в виде списка.

2.2 Получить список свойств (EnumerableOwnPropertyNames(obj, "key"))

Процесс получения списка свойств имеет множество деталей, наиболее важной из которых является вызов внутреннего метода объекта.OwnPropertyKeysполучить объектownKeys.

Примечание: в это времяownKeysТип представляет собой тип списка, который используется только для внутренней реализации.

затем объявите переменнуюproperties, тип также является типом списка, и циклownKeysдобавить каждый элемент вpropertiesСписок.

в конце концовpropertiesвернуть.

Вам может быть интересно, почему ownKeys уже является результатом, почему вы перебираете элементы списка в цикле?propertiesсередина.

Это связано с тем, что операция EnumerableOwnPropertyNames используется не только для API Object.keys, но и имеет внутри себя некоторые другие операции, но API Object.keys не используется, поэтому этот шаг кажется излишним.

Таким образом, дляObject.keysДля этого API самым важным в списке свойств является вызов внутреннего методаOwnPropertyKeysполучатьownKeys.

По сути, это внутренний метод.OwnPropertyKeysОпределяет порядок атрибутов.

оOwnPropertyKeysметодECMA-262Он описывается таким образом:

когдаOвнутренний методOwnPropertyKeysПри вызове выполняются следующие шаги (фактически один шаг):

  1. Return ! OrdinaryOwnPropertyKeys(O).

а такжеOrdinaryOwnPropertyKeysОговаривается так:

  1. объявить переменнуюkeysЗначение представляет собой пустой список (тип списка)
  2. Отсортируйте свойства каждого числового типа в порядке возрастания значения и добавьте их вkeysсередина
  3. Отсортируйте свойства каждого типа String в порядке возрастания времени создания и добавьте их вkeysсередина
  4. Отсортируйте атрибуты каждого типа символов в порядке возрастания времени создания и добавьте их вkeysсередина
  5. Будуkeysвернуть(return keys)

Вышеприведенное правило не только оговаривает порядок возврата разных типов, но также оговаривает, что если тип атрибута объекта является числом, а символ смешан с символом, то порядок возврата всегда сначала число, затем строка , и, наконец, Символ.

Например:

Object.keys({
  5: '5',
  a: 'a',
  1: '1',
  c: 'c',
  3: '3',
  b: 'b'
})
// ["1", "3", "5", "a", "c", "b"]

Хотя правила упорядочения атрибутов указываютSymbolпорядок, а по фактуObject.keysв конце концовSymbolСвойства типа отфильтровываются. (Причина в том, что правило порядка не просто даетObject.keysиспользование API, это общее правило)

2.3 Преобразуйте тип списка в массив, чтобы получить окончательный результат (CreateArrayFromList( elements ))

Теперь, когда у нас есть список свойств объекта, последний шаг — преобразовать список свойств типа List в тип Array.

Преобразование списка свойств типа List в тип Array очень просто:

  1. Сначала объявить переменнуюarray, значение представляет собой пустой массив
  2. Прокрутите список свойств, добавляя каждый элемент вarrayсередина
  3. Будуarrayвернуть

3. Это правило упорядочения также применяется к другим API.

Описанные выше сопоставления также применяются к следующим API:

  1. Object.entries
  2. Object.values
  3. for...inцикл
  4. Object.getOwnPropertyNames
  5. Reflect.ownKeys

Примечание. В дополнение к вышеуказанному APIReflect.ownKeys, другие APISymbolВведите свойства для фильтрации.