Berwin is a member of the W3C Performance Working Group and a senior front end engineer for 360 Navigation. Vue. Js early user, author of Vue. Js in Its simplest form (currently being published). The blog link

The other day a friend asked me a question: Why are the return values of Object.keys sorted automatically?

Here’s an example:

const obj = {
  100: 'one hundred'.2: '二'.7: 'seven'
}
Object.keys(obj) / / / "2", "7", "100"]
Copy the code

And this one doesn’t sort automatically, okay?

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

When my friend asked me this question, I couldn’t answer it for a while. So a look up of the ECMA262 specification, plus a later reading of the article on the subject, made it clear why such a strange thing was happening.

So this article details what happens inside when object. keys is called.

1. The answer

To conclude the above question, object. keys internally performs a different sort logic depending on the type of the attribute name key. There are three cases:

  1. If the property name is of typeNumber, thenObject.keysThe return value is based onkeySort from smallest to largest
  2. If the property name is of typeString, thenObject.keysThe return value is sorted in ascending order by the time the property was created.
  3. If the property name is of typeSymbolSo the logic is the sameStringThe same

That explains the above question.

Let’s take a closer look at what happens behind the scenes when Object.keys is called.

2. WhenObject.keysWhat happens behind the scenes when it’s called

When the object. keys function is called with the argument O, the following steps are performed:

Step 1: Convert parameters to objects of type Object.

Step 2: Get the property list Properties from the transformed object.

Note: The properties List is of type List (List type is ECMAScript specification type)

Step 3: Convert a List of properties of type List to Array for the final result.

The specification defines it as follows:

  1. callToObject(O)Assign the result to the variableobj
  2. callEnumerableOwnPropertyNames(obj, "key")Assign the result to the variablenameList
  3. callCreateArrayFromList(nameList)Get the final result

2.1 Converting parameters to Object (ToObject(O))

The ToObject operation converts the parameter O to a value of type Object according to the following table:

The parameter types The results of
Undefined Throw a TypeError
Null Throw a TypeError
Boolean Returns a new Boolean object
Number Returns a new Number object
String Returns a new String
Symbol Returns a new Symbol object
Object Return Object directly

Because of the ToObject operation inside Object.keys, object. keys can actually accept other types of parameters as well.

The table above details how different types of parameters are converted to Object types.

We can write a few simple examples to try:

First try null to get an error:

Figure 1Object.keys(null)

As shown in Figure 1, the error was reported.

Let’s try the numbers:

Figure 2Object.keys(123)

As shown in Figure 2, return an empty array.

Why is an empty array returned? See Figure 3:

Figure 3new Number(123)

As figure 3 shows, the returned object does not have any extractable properties, so it is normal to return an empty array.

Then let’s try String again:

Figure 4.Object. Keys (' I am Berwin ')

In Figure 4 we see that some String numbers are returned because strings have extractable properties, as shown in Figure 5:

Figure 5New String(' I am Berwin')

Because strings have extractable properties, the property names of strings are extracted and returned as lists.

2.2 Obtaining the attribute List (EnumerableOwnPropertyNames(obj, "key"))

There are many details to getting the property list, but one of the most important is to call the object’s internal method OwnPropertyKeys to get the object’s ownKeys.

Note: The ownKeys type at this point is List and is only used for internal implementation

Then declare the variable Properties, also of type List, and loop through ownKeys to add each element to the Properties List.

Finally, properties is returned.

You may wonder why you need to loop through the list of elements into properties when ownKeys are already the result.

It is because the EnumerableOwnPropertyNames operation is not only to the Object. Use this API keys, inside it there are some other operation, just the Object. This API is not used to the keys, so it seems that this step is redundant.

So for the Object. Keys API, the most important thing to get the property list is to call the internal method OwnPropertyKeys to get the ownKeys.

It is the internal method OwnPropertyKeys that determines the order of properties.

The OwnPropertyKeys method is described in ecMA-262 as follows:

When O’s internal method OwnPropertyKeys is called, the following steps (really just one step) are performed:

  1. Return ! OrdinaryOwnPropertyKeys(O).

OrdinaryOwnPropertyKeys specify:

  1. Declare a variablekeysThe value is an empty List (type List)
  2. Sort each of the attributes of type Number in ascending numeric order and add them tokeysIn the
  3. Sort each String property in ascending order by creation time and add it tokeysIn the
  4. Add each Symbol type property in ascending order from creation time tokeysIn the
  5. willkeysReturn (return keys)

This rule not only specifies the return order of the different types, but also specifies that if the object’s attribute type is numeric and the character is mixed with Symbol, the return order should always be numeric first, then string, and finally Symbol.

Here’s an example:

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

The order rules specify the order of symbols, but object. keys will eventually filter out properties of type Symbol. (The reason is that the order rule is not just an API for Object.keys, it is a general rule.)

2.3 Convert List to Array to get the final result (CreateArrayFromList( elements ))

Now that we have an object’s property List, the last step is to convert the property List of type List to type Array.

Converting an attribute List of type List to Array is very simple:

  1. Let’s declare a variablearrayThe value is an empty array
  2. Loop through the property list to add each element toarrayIn the
  3. willarrayreturn

3. This ordering rule also applies to other apis

The sorting rules described above also apply to the following apis:

  1. Object.entries
  2. Object.values
  3. for... incycle
  4. Object.getOwnPropertyNames
  5. Reflect.ownKeys

Note: All apis except reflect. ownKeys filter out Symbol attributes.