预分配长度可提升数组性能:使用 Array(n) 显式声明长度,引擎一次性分配连续内存,索引赋值无需扩容检查,避免重分配和中间对象。

数组创建方式直接影响 V8 等现代 JavaScript 引擎的底层存储决策、类型推断和优化路径。不同写法可能让同一逻辑触发完全不同的内存布局与执行策略,甚至导致性能差异达数倍。
预分配长度能避免多次扩容
使用 Array(n) 显式声明长度,引擎会一次性分配连续内存块,后续通过索引赋值(如 arr[i] = value)无需检查容量、不触发重分配,也不产生中间对象。
- 高效写法:
const arr = new Array(10000); for (let i = 0; i - 低效写法:
const arr = []; for (let i = 0; i —— 每次 <code>push都可能触发扩容、复制旧数据、更新隐藏类
字面量初始化决定初始元素类型
V8 根据字面量中首个若干元素的类型,为数组选定初始“元素种类”(Elements Kind),且该种类只能向下兼容(如从 PACKED_SMI_ELEMENTS → PACKED_DOUBLE_ELEMENTS → PACKED_ELEMENTS),不可回退。
- 全整数:
[1, 2, 3]→ 启用最高效的SMI模式 - 混入浮点数:
[1, 2.5, 3]→ 升级为DOUBLE模式,已有整数需装箱 - 混入字符串或对象:
[1, "a", {}]→ 跳转至通用PACKED_ELEMENTS,所有值都以堆引用形式存储
稀疏赋值强制降级为字典模式
当索引跳跃过大(如 arr[999] = 1 而前面未填充),V8 判定为稀疏数组,放弃连续内存布局,改用哈希表(Dictionary Elements)存储,访问从 O(1) 退化为平均 O(log n),且无法享受内联缓存优化。
立即学习“Java免费学习笔记(深入)”;
- 风险操作:
const arr = []; arr[10000] = "done"; - 安全替代:
const arr = new Array(10001); arr[10000] = "done";(预分配 + 密集索引)
避免运行时结构突变干扰隐藏类
数组本身是对象,其内部结构(如是否带 length 属性、是否被冻结、是否被原型污染)会影响引擎对其的优化判断。修改 Array.prototype 或对数组实例添加非常规属性,会破坏引擎的类型假设,导致所有相关操作去优化。
- 禁止:
Array.prototype.customMap = ...或arr.__meta = {...} - 推荐:
Object.freeze(Array.prototype)(启动前全局保护);用独立工具函数替代原型扩展


















