Javascript object concepts

Javascript objects are made up of groups of attributes and values like a dictionary, so the easiest way to store attributes and values is to use a dictionary, but because dictionaries are non-linear, reading is much less efficient.

To improve storage and lookup efficiency, V8 has added two hidden attributes to the object: the Sort attribute (Element) and the general attribute (Properties). The Element attribute refers to elements, where the sorted attributes are stored in order. The Properties property points to the Properties object, where the general properties are saved in the order they were created.

Sorting properties (Elements) and general properties (Properties)

In this way, many people still do not understand. Let’s write a small case to make it clear

<! DOCTYPEhtml>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>

<body>
    <script>
         window.aobj = {
            0: 'str0'.3: 'str1'.2: 'str2'.'a': 'aa'.'b': 'bb'.'c': 'cc'.'d': 'dd'.'e': 'ee',}// Add attributes dynamically
         for(let i=0; i<4; i++){ aobj[`property${i}`] = Math.random()
        } 

        console.log(aobj)
    </script>
</body>

</html>
Copy the code

Next we will open the browser developer tools, open the Memory option, and record. Through the Memory snapshot we can collect the Memory management information, and then open the window/file object. Here we can find the Memory of the aobj variable

As you can see from the above image, the aobj object not only contains the key, but also maintains two objects, elements and properties. The numeric properties in the object are called sorting properties, which are called elements in V8. Sort properties are stored in order), and string properties are called regular properties, which in V8 are called Properties (regular properties are stored in the order they were created). The aOBj object contains exactly these two hidden properties.

In V8, two linear data structures are used to store the sorted and general attributes separately in order to improve the performance of storing and accessing these two attributes. After splitting the two linear data structures, if an index is performed, V8 completes an index by reading all elements sequentially from the Elements property and then from the properties property.

So let’s verify printing

If I’m walking through an object property

  1. The numeric attributes are printed first and in order of numeric size
  2. The string properties set are printed in the same order as before

Reason: The ECMAScript specification defines that numeric attributes should be sorted in ascending order by index value size, and string attributes in ascending order by order of creation

Let’s do it again

<script>
        function Foo() {
            this[100] = 'test-100'
            this[1] = 'test-1'
            this["B"] = 'bar-B'
            this[50] = 'test-50'
            this[9] = 'test-9'
            this[8] = 'test-8'
            this[3] = 'test-3'
            this[5] = 'test-5'
            this["A"] = 'bar-A'
            this["C"] = 'bar-C'
        }
        var bar = new Foo()
        for (key in bar) {
            console.log(`index:${key} value:${bar[key]}`)}console.log(bar);
    </script>
Copy the code

The memory structure of the BAR object is shown below

When we do not find properties in the browser’s memory snapshot, the reason is that the statement bar.B looks for B’s property value, and V8 looks for the object properties that the properties property points to. The B attribute is then looked up in the Properties object, which adds an extra step to the lookup process and thus compromises the efficiency of the element’s lookup. So V8 uses a tradeoff strategy to speed up finding properties by storing some of the general properties directly into the object itself, which we call in-object properties. You can see how objects are represented in memory:

However, the number of attributes in an object is fixed, 10 by default, and if you add attributes that exceed the space allocated by the object, they are stored in the regular property store. Although the property store has an additional layer of indirection, it can be expanded freely.

<script>
        // Let's test V8
        function Foo(property_num, element_num) {
            // Add indexable attributes
            for (let i = 0; i < element_num; i++) {
                this[i] = `element${i}`
            }
            // Add general attributes
            for (let i = 0; i < property_num; i++) {
                let ppt = `property${i}`
                this[ppt] = ppt; }}var bar = new Foo(10.10)
    </script>
Copy the code

This example normally has 10 properties, so there is no properties object, as shown below:

This is the time when there is no properties object

When we set the number of general properties to 20 let’s see what the memory snapshot of bar looks like, as shown below

 <script>
        // Let's test V8
        function Foo(property_num, element_num) {
            // Add indexable attributes
            for (let i = 0; i < element_num; i++) {
                this[i] = `element${i}`
            }
            // Add general attributes
            for (let i = 0; i < property_num; i++) {
                let ppt = `property${i}`
                this[ppt] = ppt; }}var bar = new Foo(20.10)
    </script>
Copy the code

The extra general properties are placed in the Properties object, similar to the structure shown in the following figure

Stored in the properties of linear data structure called “properties”, because only need by index in linear data structure that can access to the property, although the access speed of linear structure, but if from linear structure add or delete a large number of attributes, the execution efficiency is very low, this is mainly because will produce a lot of time and memory overhead. Therefore, if an object has too many attributes, V8 adopts another storage strategy, the “slow attribute” strategy, but the slow attribute objects have independent nonlinear data structures (dictionaries) inside them as property storage containers. All attribute meta-information is no longer stored linearly, but is stored directly in the attribute dictionary.

The introduction of these two attributes speeds up V8’s ability to find attributes. To further improve efficiency, V8 also implements a strategy of built-in attributes, which saves an intermediate step by writing them directly into objects when there are fewer than a certain number of common attributes.

Finally, if there are too many attributes in the object, or if there are repeated operations to add or remove attributes, V8 will downgrade the linear storage mode to the nonlinear dictionary storage mode, which will slow down the lookup but speed up the modification of the object’s attributes.

conclusion

To improve storage and lookup efficiency, V8 adds two hidden attributes to the object, element and properties.

When the key of an object is a number, it is added to the Element object. When more than 10 general properties are initialized, the excess data is added to the Properties object for maintenance or dynamically added properties are added to the Properties object.

When accessing an attribute, first search the linear structure element or properties, and then search the regular attribute. This is to speed up the search efficiency

reference

V8. Dev/blog/fast – p…