JavaScript 引擎基础: Shapes

前言

在js的对象中,每个key映射的属性值都带有一套*property attributes*.

如上图所示,get,set,writable等属性,虽然在我们平时的编码中,很多时候可能不需要使用,但是js任然要对对象的每一个属性都维护一套property attributes.这样无形之中,大大增加了js的内存消耗,那么在js中,是用什么方法对其进行优化的呢?

Shapes

什么是shape

js中,将一个类对应的属性数据结构称为Shape

如上图所示,有包含x,y的对象Object, js将其分作两部分来存储。JSObject类似于一个只包含x,y的值的数组,和一个包含了x,yproperty attributes的shape。JSObject中的value按顺序对应shape中的property attributes的shape。

这样在面对大量结构相同的对象时,只需要存储一套Shape,在单独维护JSObject中的value即可,大大减小了性能开销

例如上图所示,a,b两个对象便可以复用一套shape。

shape的深入优化

js 复制代码
const point = {};  
point.x = 4;  
point.y = 5;  
point.z = 6;

在上面的代码中,js引擎并不会对一个shape进行多次修改,而是生成3个shape,以链状的形式排列。

这种优化方式,例如在处理包含非常多属性的对象时,对其增加或者删除属性,就不需要重新维护一个其的赋值shape,有效减小内存开销。

如果对象中的属性太多,shape的链条太长,js引擎还会维护一个shapeTable来索引Shape,减小了链式查找带来的性能开销。

注意: 添加特性的顺序会影响shape结构。例如,{x:4,y:5}会产生与{y:5,x:4}不同的shape。

而对于Array来说,则不需要特定存住其shape,因为Array所有的属性的property attributes一般都是默认的。也可以用defineProperty修改,但是及其不推荐。

shape的实际场景分析

现在有如下两个生成对象的方法

js 复制代码
<button onclick="samllFunc()">内存小方式</button>
<button onclick="bigFunc()">内存大方式</button>
<script>
    let list = [];
    function samllFunc() {
        function addKey(item) {
            for(let i = 0; i < 10000; i++) {
                item[i] = 1;
            }
            return item
        }
        let res = [];
        for(let i = 0; i < 10000; i++) {
            res.push(addKey({}))
        }
        list.push(res)
        console.log(res.length)
    }
    function bigFunc() {
        function addKey(item, key) {
            for(let i = 0; i < 10000; i++) {
                item[i + key] = 1;
            }
            return item
        }
        let res = [];
        for(let i = 0; i < 10000; i++) {
            res.push(addKey({}, i))
        }
        list.push(res)
        console.log(res.length)
    }
</script>

都是生成10000个10000个属性的对象,smallFunc中的对象都含有相同的shape,bigFunc中的对象shape各不相同。

相同的shape快照:

不同的shape快照:

对比可以看出,两者的差距是非常大的。 、

总结

基于对shape的理解,我们确定了一些有助于提高性能的实用JavaScript编码技巧:

  1. 总是以相同的方式初始化对象,这样它们就有相同的形状可以复用。
  2. 不要扰乱数组元素的属性,这样可以有效地存储和操作它们。

参考文章

mathiasbynens.be/notes/shape...

相关推荐
wshzd2 分钟前
LLM之Agent(104)|DeepSeek-Harness(十三)ReactLoopAgent 总览:kick → turn → step
开发语言·前端·javascript
茉莉玫瑰花茶9 分钟前
OpenGL [ 基础概念 ]
java·前端·数据库
随性而行36016 分钟前
企业微信二次开发如何接入大模型工具?API接口实现智能任务调用的技术思路
java·前端·人工智能·python·微信·机器人·企业微信
IMPYLH25 分钟前
HTML 的 <td> 元素
前端·html
艺杯羹35 分钟前
240GB流量击穿与频繁OOM:从云端瘫痪到客户端自治的本地优先架构重构实录
性能优化·系统架构·fastapi·桌面客户端·本地优先
gnip36 分钟前
Flutter GetX 三件套开发规范(Skill)
前端·flutter
张小姐的猫1 小时前
【AI大模型接入SDK】 —— 前端页面 & 项目总结与拓展
前端·数据结构·数据库·c++·人工智能·chatgpt
web打印社区1 小时前
远程打印:WebSocket 与 HTTP 轮询怎么选
前端·vue.js·websocket·网络协议·http·electron·pdf
吴声子夜歌1 小时前
HTML——庞杂的表单控件元素(一)
前端·html
天天喝旺仔1 小时前
浏览器渲染原理:从解析 HTML/CSS、构建渲染树到重排重绘与首屏优化
前端·javascript·css·性能优化·html