最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • javascript对象的v8底层原理实现

    正文概述 掘金(bug小能手)   2020-12-09   521

    javascript对象概念

    javascript 对象像⼀个字典是由⼀组组属性和值组成的,所以最简单的⽅式是使⽤⼀个字典来保存属性和值,但是由于字典是⾮线性结构,所以如果使⽤字典,读取效率会⼤⼤降低。

    V8 为了提升存储和查找效率,V8 在对象中添加了两个隐藏属性,排序属性(element)和常规属性(properties),element 属性指向了elements 对象,在 elements 对象中,会按照顺序存放排序属性。properties 属性则指向了 properties 对象,在properties 对象中,会按照创建时的顺序保存常规属性。

    排序属性(elements)和常规属性(properties)

    这样子讲很多人还不是很理解,下面我们写一个小小的案例来说清楚

    <!DOCTYPE html>
    <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',
            }
    				//  动态添加属性
             for(let i=0; i<4;i++){
                aobj[`property${i}`] = Math.random()
            } 
    
            console.log(aobj)
        </script>
    </body>
    
    </html>
    

    接下来我们打开浏览器开发者工具,打开Memory选项,然后录制,通过内存快照我们可以收集内存管理的信息,然后打开window/file对象,这里可以找到aobj变量的内存是怎么样的,如下图

    javascript对象的v8底层原理实现

    通过上面的图片我们可以看到aobj对象里面不仅有我们定义的key,同时还维护了elements和properties这两个对象,在对象中的数字属性称为排序属性,在 V8 中被称为 elements(elements 对象中,会按照顺序存放排序属性),字符串属性就被称为常规属性,在 V8 中被称为 properties(按照创建时的顺序保存了常规属性)。aobj 对象恰好包含了这两个隐藏属性。

    在 V8 内部,为了有效地提升存储和访问这两种属性的性能,分别使⽤了两个线性数据结构来分别保存排序属性和常规属性。分解成这两种线性数据结构之后,如果执⾏索引操作,那么 V8 会先从elements 属性中按照顺序读取所有的元素,然后再在 properties 属性中读取所有的元素,这样就完成⼀次索引操作。

    我们来验证打印⼀下

    javascript对象的v8底层原理实现

    javascript对象的v8底层原理实现

    如果在遍历对象属性的时候

    1. 数字属性被最先打印出来了,并且是按照数字⼤⼩的顺序打印的
    2. 设置的字符串属性依然是按照之前的设置顺序打印的

    原因:ECMAScript 规范中定义了数字属性应该按照索引值⼤⼩升序排列,字符串属性根据创建时的顺序升序排列

    下面我们再举个例子

    <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>
    

    bar对象的内存结构如下图 javascript对象的v8底层原理实现

    当我们在浏览器⾥内存快照中,并没有发现 properties,原因是bar.B这个语句来查找 B 的属性值,那么在 V8会先查找出 properties 属性所指向的对象 properties,然后再在 properties 对象中查找 B 属性,这种⽅式在查找过程中增加了⼀步操作,因此会影响到元素的查找效率。所以V8 采取了⼀个权衡的策略以加快查找属性的效率,这个策略是将部分常规属性直接存储到对象本身,我们把 这称为对象内属性 (in-object properties)。对象在内存中的展现形式你可以参看下图: javascript对象的v8底层原理实现

    不过对象内属性的数量是固定的,默认是 10 个,如果添加的属性超出了对象分配的空间,则它们将被保存在常规属性存储中。虽然属性存储多了⼀层间接层,但可以⾃由地扩容。

    <script>
            //我们⼀起测试⼀下V8
            function Foo(property_num, element_num) {
                //添加可索引属性
                for (let i = 0; i < element_num; i++) {
                    this[i] = `element${i}`
                }
                //添加常规属性
                for (let i = 0; i < property_num; i++) {
                    let ppt = `property${i}`
                    this[ppt] = ppt;
                }
            }
            var bar = new Foo(10, 10)
        </script>
    

    这个例子的常规属性是10个,所以此时是没有properties对象的,如下图: javascript对象的v8底层原理实现

    这个是时候是没有properties对象的

    当我们把常规属性的数量设置为20的时候我们来看看bar此时的内存快照是怎么样的,如下图

     <script>
            //我们⼀起测试⼀下V8
            function Foo(property_num, element_num) {
                //添加可索引属性
                for (let i = 0; i < element_num; i++) {
                    this[i] = `element${i}`
                }
                //添加常规属性
                for (let i = 0; i < property_num; i++) {
                    let ppt = `property${i}`
                    this[ppt] = ppt;
                }
            }
            var bar = new Foo(20, 10)
        </script>
    

    javascript对象的v8底层原理实现

    这里会把超出来的常规属性放在properties对象中去,类似下面的图的结构 javascript对象的v8底层原理实现

    保存在线性数据结构中的属性称之为“快属性”,因为线性数据结构中只需要通过索引即可以访问到属性,虽然访问线性结构的速度快,但是如果从线性结构中添加或者删除⼤量的属性时,则执⾏效率会⾮常低,这主要因为会产⽣⼤量时间和内存开销。因此,如果⼀个对象的属性过多时,V8 就会采取另外⼀种存储策略,那就是“慢属性”策略,但慢属性的对象内部会有独⽴的⾮线性数据结构 (词典) 作为属性存储容器。所有的属性元信息不再是线性存储的,⽽是直接保存在属性字典中。

    通过引⼊这两个属性,加速了 V8 查找属性的速度,为了更加进⼀步提升查找效率,V8 还实现了内置属性的策略,当常规属性少于⼀定数量时,V8 就会将这些常规属性直接写进对象中,这样⼜节省了⼀个中间步骤。

    最后如果对象中的属性过多时,或者存在反复添加或者删除属性的操作,那么 V8 就会将线性的存储模式降级为⾮线性的字典存储模式,这样虽然降低了查找速度,但是却提升了修改对象的属性的速度。

    总结

    javascript对象在V8底层 为了提升存储和查找效率,V8 在对象中添加了两个隐藏属性,排序属性(element)和常规属性(properties)

    对象的key是数字的时候会添加到element对象中去,当初始化的常规属性超过10个的时候会把超过的数据添加到properties对象中去维护或者是动态的添加属性也会放在properties中去。

    当访问属性的时候,先去element或者properties两个线性结构里面查找,查找不到再去常规属性查找,这样子是为了加快查找效率

    参考

    v8.dev/blog/fast-p…


    起源地下载网 » javascript对象的v8底层原理实现

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元