JS 数据结构[数组]实现

208 阅读2分钟

数组

数组(Array)是一种线性表数据结构。它用一组连续的存储空间来存储一组具有相同类型的数据

线性表

数据排成一列,每个数据最多有前后两个方向。数组链表队列栈都是线性表。

连续内存空间、相同数据类型

因为连续内存空间,获得随机访问特性。但是写入速度慢。注意:随机访问的时间复杂度是O(1)查找时间复杂度是O(n)

不过也因为连续内存空间,需要向系统申请固定长度内存空间来存储。过长或过短时可以启用扩容缩容策略。

JS代码实现

JS原本就有Array对象,但是它不是纯粹的数组结构。先来看段代码:

let arr = [100, 12.3, 'red', 'blue', {}];
arr[arr.length] = [];
arr.length // 6
arr[arr.length - 1] // []

发现有这些问题:

  • 数组可以添加多种类型
  • 数组没有固定长度,似乎可以自动扩容

V8引擎中的数组实现

  • Array的基类是Object,所以可以存储不同的类型
  • 数组基于两种形式存在
    • 快数组,基于数组实现
    • 慢数组,基于散列表实现
  • 快数组会自动扩缩容
  • 快慢数组的区别
    • 存储方式:快数组是在内存中是连续的,慢数组是零散的
    • 优势:快数组遍历、查找效率略高,慢数组内存空间利用率高。
  • 当满足特定条件时,数组会在快数组慢数组间自动切换。

代码实现

我们要实现的功能包括:

  • 指定数组长度
  • 统一数据类型
  • 随机访问,时间复杂度O(1)
  • 查询,时间复杂度O(n)
class MyArray extends Array {
  constructor () {
    if (!arguments.length) throw new Error('缺少必要参数:space')
    if (typeof arguments[0] !== 'number') throw new Error('分配内存空间必须为数字')
    const argLength = arguments.length - 1
    const array = [...arguments].filter((i, k) => k !== 0)
    if (array.length >= arguments[0]) throw new Error('数组长度超出分配空间')
    super(...array)
    this.space = arguments[0]
    this.type = null
    if (array.length) {
      const { type, objectType } = this._getType(arguments[1])
      this.type = type
      this.objectType = objectType
    }
    if (argLength > 1) {
      if (!this._isSameType(array)) {
        throw new Error('数组类型必须一致')
      }
    }
  }

  // 获取对象类型
  _getType (target) {
    const type = typeof target
    return {
      type,
      objectType: type === 'object'
        ? Object.getPrototypeOf(target).constructor
        : null
    }
  }

  // 获取数组是否同一类型
  _isSameType (arr) {
    for (let i = 0; i < arr.length; i++) {
      if (this.objectType === null) {
        if (typeof arr[i] !== this.type) return false
      } else {
        if (!(arr[i] instanceof this.objectType)) return false
      }
    }
    return true
  }

  // 添加元素
  push (...arg) {
    if (this.length + arg.length > this.space) {
      throw new Error('数组长度超出分配空间')
    }
    if (!this._isSameType(arg)) {
      throw new Error('数组类型必须一致')
    }
    Array.prototype.push.call(this, ...arg)
  }
}

function A() {}
function B() {}
var a1 = new A()
var a2 = new A()
var b1 = new B()
var arr = new MyArray(4, a1, a2)
arr.push(a1)
// arr.push(b1) // error 类型错误
// arr.push('a') // error 类型错误
// arr.push(a1, a2) // error 超出长度
console.log(arr)

当然还有很多可以完善的地方,这里就不细写了。

原创不易,欲转先告知,欢迎加我交流:

image.png