array splice php w3c,深入一点 - 为什么说splice 效率低呢

我们在使用 Array.prototype.splice 方法的时候,都会提及说它速度慢,效率低。尤其在例如 Vue或者React 框架中也不推荐使用,原因是为什么呢?

splice 方法

方法介绍如下:

05a4a133e4ae133aa2429861a15e0166.png

方法也比较明了,就是在数组内删除或者添加元素。

如下示例:

// 添加一个元素

const arr = [1, 2, 3]

arr.splice(1, 0, 2, 3)

// [1, 2, 3, 2, 3]

// 删除元素

arr.splice(2, 2)

// arr: [1, 2, 3]

返回值则是删除元素的数组,若是添加就是空数组.

w3c 执行过程

在 w3c 中关于 splice 是如何描述过程的呢?

Array.prototype.splice 位于ecmascript 规范中 15.4 数组章节下面的 15.4.4.12 点击这了即可

下面看关于 splice描述:

12cfc404292bff505f97056271ea2536.png

e6bcf5696d383dec85b1ca18fa46b353.png

下面就用删除和添加两个例子来说明规范的操作过程:

在规范里面共有 17步的数据操作:

第2步中,splice引入了新组数 A,用来存返回数据结果

第6,7步中,得到真实开始位置与删除个数,在这里进行边界判断

第9步这里判断当前是否是删除,若 actualDeleteCount > 0即为删除,然后得到A的删除数组,这里就获取到了要删除的元素,若删除元素个数为0,则跳过A为空数组,k 为0, 否则 k为删除个数,A 为删除元素集合. actualStart 为传入的数组中某个下标值, actualDeleteCount 为传入某个个数范围是 0-len

在12步判断添加元素是否多与删除个数,若少于删除个数,数组长度减少。

第13步判断添加元素多余删除元素个数,数组长度增加。见下图示

第14步初始化开始位置,也就是变量k

第15步中进行元素位置移动,如果添加则会不断把元素添加到元素内

第16步中计算length,元素长度是由原始长度减去删除元素加上增加元素的数量。

最后一步就是返回在第9步中得到移除的元素A.

在 splice 方法中,我们会使用情况如下:

删除元素

添加元素

删除同时添加元素

删除元素在第9步处理删除元素数组,第12步处理元素前移并删除结尾的元素。添加元素在13步内处理元素后移,并在15步在对应下标下放入元素。删除元素同时删除上面每一步都会走到。

关于规范一些内部方法说明:

[[HasProperty]](P) 对象上的内部方法,若通过P得到对象结果为undefined则为false,否则为true。

[[GET]](P) 对象内部方法,通过属性名P获取结果。

[[Put]](P, V, Throw) 设置对象属性P的值为V,Throw若为true,遇到错误则会抛出TypeError。

[[Delete]](P, Throw) 删除对象上属性P,若Throw为true,遇到错误则抛出TypeError.

图示一个数组删除数量多于添加数量

操作数组:

[0, 1, 2, 3]

这里进行 splice(1, 2, 4) 操作,从下标1位置移除2个元素,并添加一个元素

c044f9791d61116da35bc7146ed0895e.png

图示一个数组添加多余删除个数

[0, 1, 2, 3]

进行 splice(1, 1, 5, 6) 操作,从下标1的位置删除一个元素,并插入 5和6的示例。

9a0adca03ca380bd7f509c960d94155a.png

总结

通过上面规范分析和图示分析,其实splice之所以”慢“, 是因为每次splice操作除了需要分配新的内存区域去存储数据外,还需要不断操作元素的下标,大量移动元素位置,若start=0,岂不是每个元素都需要移动一次呢?这就是说效率不高原因。

tips: splice 会修改数组本身,所以在vue和react中数组数据变化不会导致UI变化的原因之一。

其他参考:

更好的插入或者删除方式

上面说splice 用于三种情况:

删除元素

添加元素

删除同时添加元素

在最新的ecma中有新的方法可以替代splice用途

删除数组

使用 filter 代替:

const arr = [1, 2, 3, 4]

// 删除下标为2的元素

const newArray = arr.filter((_, index) => index !== 2)

// [1, 2, 4]

添加元素

使用 concat 或者 spread 代替配合 slice 实现任何位置插入:

const array = [1, 2, 3,]

// 下标1 插入10

const newArray = array.slice(0, 1).concat(10, array.slice(1))

// [1, 10, 2, 3]

// const newArray = [...array.slice(0, 1), 10, array.slice(1)]

添加删除元素

同上

const array = [0, 1, 2, 3, 4, 5]

// 下标位置2位置删除2个,并插入7,8,9

const newArray = array.slice(0, 2).concat([7, 8, 9], array.slice(4))

// [0, 1, 7, 8, 9, 4, 5]

最后

相信自己,总会有一个办法解决问题,代码性能也会一点点提高,欢迎交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值