返回
揭秘 Array 常用 API 背后的数据结构与算法奥秘
IOS
2023-09-03 19:52:54
**前言**
数组(Array)是一种在编程中广泛运用的数据结构,它以有序的方式存储一组具有相同数据类型的同质化数据。JavaScript 内置的 Array 对象提供了丰富的 API,可以轻松地对数组进行各种增删改查等常见操 作,为开发人员提供了极佳的灵活性和便利性。
然而,在实际编程场景中,如果仅仅停留在使用层面,难免会遇到性能瓶颈或难以预料的边缘场景。要进阶为一名资深开发者,就需要跳出 API 的使用层面,从数据结构与算法层面真正吃透 Array 的内部运作原理,才能在面对复杂场景时游刃有余,从容应对。
**一、Array 的数据结构**
JavaScript 中的 Array 采用**基于原生的固定长度数组(Contiguous Array)** 的数据结构。这意味着,与链表等数据结构中可以通过指针前后连接的方式存储数据,在 Array 中数据的存储是紧凑、有序的。举个形象的比喻,我们可以将 Array 视作一个个首尾相连的火车车厢,每个车厢都装载着一个确定的数据。
**二、Array 常用 API 原理剖析**
有了对 Array 的数据结构的初步认识,就可以顺藤摸瓜地探究其常用 API 背后的原理了。
**1. 添加与长度**
* push():在数组尾部压入一个或多个新项,并自动调整数组的 length 长度属性。时间复杂度为 O(1),因为不需要额外遍历或内存重新申请等开销。
* pop():移除数组尾部的一个项,并自动调整 length。时间复杂度同样为 O(1)。
* unshift():在数组头部压入一个或多个新项,并自动调整 length。由于需要为新项在原有数据的基础上重新申请内存,其时间复杂度为 O(n)。
* shift():移除数组头部的一个项,并自动调整 length。和 unshift() 相反,时间复杂度也为 O(n)。
* length:获取或设定数组的长度。
**2. 删除与替换**
* delete arr[i]:ES5 的写法,可以按照下标从数组中移除指定的项。需要注意,与 pop() / shift() 不同的,该 API 执行后会产生一个值为 undefined 的洞(Hole);
* arr[i] = undefined:也可以达到和 delete 操作相类似的效果,但与 delete 仍然有细微差别。
* arr.splice(i, n, ...items):JavaScript 中真正意义上从指定下标 i 处开始,按照给定 n 的值,用给定的 items 替换指定数量的项。其时间复杂度与被替换项数量 n 呈线性增长,即 O(n)。
**3. 遍历与搜索**
* for 循环(ES5):遍历数组中最常用的方法,但效率较低,随着数组长度的增大,时间复杂度达到 O(n)。
* forEach():ES5 以后新增的 API,原理上与 for 循环一致,但由内部引擎优化,循环体内部不能中断循环,也未暴露 index/value 等信息。需要注意,它也不能直接中止循环,建议使用新出的 for-of 替代。
* find():用于在数组中找到第一个满足给定断言的项,时间复杂度为 O(n)。
* findIndex():类似于 find(),但用于找出第一个满足断言的项的下标,时间复杂度同样为 O(n)。
* includes():用于判断数组中是否存在给定值,采用严格相等判断,时间复杂度为 O(n)。
**三、进阶优化:从数据结构与算法角度谈性能**
在上述内容的基础上,我们可以再进一步,从数据结构与算法的角度出发,探讨如何针对特定场景优化 Array 的使用,提升性能。
**1. 巧妙使用 splice()**
splice() 虽说是替换指定范围的数据,但也可以灵活运用它来进行数组的增删改查操 作。
* 批量新增:将多个项依次压入数组尾部,会逐次触发长度调整,导致性能损耗。可优化为将 items 连接成一个新字符串,再使用 splice() 一次性替换到指定下标。
* 批量移除:与其重复调用 pop(),不如找到要移除项的最小下标和最大的下标,使用 splice() 一次性移除掉。
**2. 优化数据遍历:for-of 与 forEach 的区别与选择**
遍历数组时,首选使用 for-of,它与 forEach 的时间复杂度一致,都是 O(n),但 for-of 更直观、可控,循环体内部可以使用 break 语句中断循环。
**四、总结与展望**
从数据结构与算法的角度剖析 Array 常用 API 的原理,有助于开发者在使用 API 的过程中,对其复杂度与适用场景有更深的认知,避免盲目使用,针对特定场景选择最优方案,大幅提升 Array 使用的熟练度和工程效率。
而随着时代进步,前端领域对数据结构与算法的要求也在不断提高,这部分内容在掌握 Array 的常用 API 使用后,是进阶为一名资深前端开发工程师的必修课。建议有志于此的开发者,可以从算法入门,逐步进阶到数据结构与算法的数据结构与算法,进一步提升自身的技术实力和思维格局。