unshift()时间复杂度为o(n),数组越长性能越差;push()为o(1),始终高效。5万元素下unshift 100次超300ms,push同量仅

直接看执行耗时最可靠:当数组长度超过 1 万,unshift() 的耗时会明显跳升,而 push() 仍保持稳定。这不是“有点慢”,而是底层机制决定的线性恶化——数组越长,unshift() 越不可控。
看时间复杂度差异
两者表面都是“加一个元素”,但行为本质不同:
- push():在末尾追加,不移动任何已有元素,时间复杂度 ≈ O(1)
- unshift():在开头插入,必须把所有现存元素索引 +1,逐个往后搬,时间复杂度 = O(n),n 就是当前数组长度
这意味着:数组有 10 万个元素时,一次 unshift() 就要搬运 10 万次内存;100 万时就是百万级操作。而 push() 始终只做一次写入。
用简单测试快速验证
不用压测工具,几行代码就能暴露问题:
const bigArr = new Array(50000).fill(0);
<p>console.time('unshift 50k');
for (let i = 0; i 300ms</p><p>const smallArr = [];
console.time('push 50k');
for (let i = 0; i </p><p>差距百倍起跳,且随着初始数组变长,<code>unshift</code> 耗时几乎线性增长。</p><h3>观察运行时表现异常</h3><p>这些现象往往暗示你在高频场景误用了 <code>unshift()</code>:</p>
- 页面滚动或动画出现卡顿,尤其在加载新数据后
- 控制台 Profile 中看到大量
Array.prototype.unshift占用主线程时间 - 消息队列消费变慢,明明只有几百条消息,处理延迟却达秒级
- 使用
shift()配合unshift()实现 FIFO 时,每轮循环耗时递增
替代方案不是“换写法”,而是换模型
别试图用 reverse() + push() 来“优化”unshift()——那只是把代价延后到反转时刻。真正有效的方式是:
- 把“头部添加”语义转为“尾部添加 + 反向读取”:新数据
push()进去,遍历时从arr.length - 1往前取 - 维护游标代替真实删除:例如用
{ items: [...], head: 0 }模拟队列,shift()只是return items[head++] - 引入真正 O(1) 首尾操作的数据结构,如
@datastructures-js/deque,内部用双数组或链表实现
性能衰减不是 bug,是设计使然。识别它,是为了及时切换抽象层级,而不是在错误的路径上反复调优。










