Автор этой статьи: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Типы выполняют различную логику сортировки. Есть три случая:
- Если тип имени свойства
Number,ТакObject.keysВозвращаемое значение соответствуетkeyСортировать от меньшего к большему - Если тип имени свойства
String,ТакObject.keysВозвращаемое значение сортируется в порядке возрастания по времени создания свойства. - Если тип имени свойства
Symbol, то логичноStringтакой же
Это объясняет проблему выше.
Ниже мы подробно знакомимObject.keysКогда звонят, что происходит за кулисами.
2. КогдаObject.keysчто происходит за кулисами, когда это называется
когдаObject.keysфункция с параметрамиOПри вызове выполняются следующие действия:
Шаг 1: Преобразуйте параметры вObjectтип объекта.
Шаг 2: Получите список свойств через преобразованный объектproperties.
Примечание. Список свойств
propertiesимеет тип Список (Тип спискадаКанонический тип ECMAScript)
Шаг 3: Перечислите свойства типа спискаpropertiesПреобразуйте в массив, чтобы получить окончательный результат.
Спецификация определяет это так:
- передача
ToObject(O)присвоить результат переменнойobj- передача
EnumerableOwnPropertyNames(obj, "key")присвоить результат переменнойnameList- передача
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Будет ли он сообщать об ошибке:
фигура 1
Object.keys(null)
Как показано на рисунке 1, действительно сообщается об ошибке.
Далее пробуем эффект чисел:
фигура 2
Object.keys(123)
Как показано на рисунке 2, возвращается пустой массив.
Почему он возвращает пустой массив? См. рисунок 3:
изображение 3
new Number(123)
Как показано на рис. 3, возвращаемый объект не имеет каких-либо извлекаемых свойств, поэтому возвращение пустого массива также является нормальным явлением.
Затем мы снова пробуем эффект String:
Рисунок 4
Object.keys('我是Berwin')
На рис. 4 мы увидим, что возвращаются некоторые числа строкового типа, поскольку объект String имеет извлекаемые свойства, см. рис. 5:
Рисунок 5
new 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При вызове выполняются следующие шаги (фактически один шаг):
Return ! OrdinaryOwnPropertyKeys(O).
а такжеOrdinaryOwnPropertyKeysОговаривается так:
- объявить переменную
keysЗначение представляет собой пустой список (тип списка) - Отсортируйте свойства каждого числового типа в порядке возрастания значения и добавьте их в
keysсередина - Отсортируйте свойства каждого типа String в порядке возрастания времени создания и добавьте их в
keysсередина - Отсортируйте атрибуты каждого типа символов в порядке возрастания времени создания и добавьте их в
keysсередина - Буду
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 очень просто:
- Сначала объявить переменную
array, значение представляет собой пустой массив - Прокрутите список свойств, добавляя каждый элемент в
arrayсередина - Буду
arrayвернуть
3. Это правило упорядочения также применяется к другим API.
Описанные выше сопоставления также применяются к следующим API:
Object.entriesObject.values-
for...inцикл Object.getOwnPropertyNamesReflect.ownKeys
Примечание. В дополнение к вышеуказанному API
Reflect.ownKeys, другие APISymbolВведите свойства для фильтрации.