返回

以纯JS实现常用数组API,揭秘数组底层运作机制

前端

了解数组的基础知识

数组是一种数据结构,用于存储一组有序的数据项。每个数据项都存储在一个称为元素的单元格中,这些元素可以通过索引来访问。数组是JavaScript中非常重要的数据类型,广泛应用于各种场景,包括存储数据、处理数据以及算法实现等。

实现常见的数组API

为了更好地理解数组的底层机制,我们将使用纯JavaScript实现一些常见的数组API。这些API包括:

  • Array.from()
  • Array.of()
  • Array.prototype.map()
  • Array.prototype.filter()
  • Array.prototype.reduce()
  • Array.prototype.sort()
  • Array.prototype.splice()

Array.from()

Array.from()方法将一个类数组对象或可迭代对象转换为真正的数组。它的语法如下:

Array.from(object, mapFn, thisArg)

其中:

  • object:要转换的对象。
  • mapFn:可选的映射函数,用于将每个元素映射到新的数组中。
  • thisArg:可选的this值,用于执行映射函数。

我们使用纯JavaScript实现Array.from()方法如下:

function arrayFrom(object, mapFn, thisArg) {
  if (!object) {
    throw new TypeError('Cannot convert undefined or null to object');
  }

  const length = object.length;
  const result = new Array(length);

  for (let i = 0; i < length; i++) {
    const value = object[i];
    if (mapFn) {
      result[i] = mapFn.call(thisArg, value, i, object);
    } else {
      result[i] = value;
    }
  }

  return result;
}

Array.of()

Array.of()方法创建一个新的数组,其中包含指定数量的元素。它的语法如下:

Array.of(element1, element2, ..., elementN)

其中,element1element2、...、elementN是要添加到新数组中的元素。

我们使用纯JavaScript实现Array.of()方法如下:

function arrayOf(...elements) {
  const length = elements.length;
  const result = new Array(length);

  for (let i = 0; i < length; i++) {
    result[i] = elements[i];
  }

  return result;
}

Array.prototype.map()

Array.prototype.map()方法创建一个新数组,其中包含对原始数组中每个元素应用指定映射函数的结果。它的语法如下:

array.map(mapFn, thisArg)

其中:

  • mapFn:要应用的映射函数。
  • thisArg:可选的this值,用于执行映射函数。

我们使用纯JavaScript实现Array.prototype.map()方法如下:

Array.prototype.map = function(mapFn, thisArg) {
  const length = this.length;
  const result = new Array(length);

  for (let i = 0; i < length; i++) {
    const value = this[i];
    result[i] = mapFn.call(thisArg, value, i, this);
  }

  return result;
};

Array.prototype.filter()

Array.prototype.filter()方法创建一个新数组,其中包含通过指定过滤函数测试的原始数组的元素。它的语法如下:

array.filter(filterFn, thisArg)

其中:

  • filterFn:要应用的过滤函数。
  • thisArg:可选的this值,用于执行过滤函数。

我们使用纯JavaScript实现Array.prototype.filter()方法如下:

Array.prototype.filter = function(filterFn, thisArg) {
  const length = this.length;
  const result = [];

  for (let i = 0; i < length; i++) {
    const value = this[i];
    if (filterFn.call(thisArg, value, i, this)) {
      result.push(value);
    }
  }

  return result;
};

Array.prototype.reduce()

Array.prototype.reduce()方法对数组中的每个元素执行一个reducer函数,并将结果汇总为一个单一值。它的语法如下:

array.reduce(reducerFn, initialValue)

其中:

  • reducerFn:要应用的reducer函数。
  • initialValue:可选的初始值,用于作为第一次调用reducer函数时的第一个参数。

我们使用纯JavaScript实现Array.prototype.reduce()方法如下:

Array.prototype.reduce = function(reducerFn, initialValue) {
  const length = this.length;
  let accumulator = initialValue;

  for (let i = 0; i < length; i++) {
    const value = this[i];
    accumulator = reducerFn(accumulator, value, i, this);
  }

  return accumulator;
};

Array.prototype.sort()

Array.prototype.sort()方法对数组中的元素进行排序。它的语法如下:

array.sort(compareFn)

其中:

  • compareFn:可选的比较函数,用于确定数组元素的排序顺序。

我们使用纯JavaScript实现Array.prototype.sort()方法如下:

Array.prototype.sort = function(compareFn) {
  const length = this.length;

  for (let i = 0; i < length; i++) {
    for (let j = i + 1; j < length; j++) {
      const a = this[i];
      const b = this[j];
      const comparisonResult = compareFn ? compareFn(a, b) : a - b;

      if (comparisonResult > 0) {
        const temp = this[i];
        this[i] = this[j];
        this[j] = temp;
      }
    }
  }

  return this;
};

Array.prototype.splice()

Array.prototype.splice()方法从数组中添加或删除元素。它的语法如下:

array.splice(start, deleteCount, ...items)

其中:

  • start:要开始添加或删除元素的索引。
  • deleteCount:要删除的元素的数量。
  • items:要添加到数组中的元素。

我们使用纯JavaScript实现Array.prototype.splice()方法如下:

Array.prototype.splice = function(start, deleteCount, ...items) {
  const length = this.length;
  const deletedItems = this.slice(start, start + deleteCount);
  const newLength = length - deleteCount + items.length;
  const result = new Array(newLength);

  for (let i = 0; i < start; i++) {
    result[i] = this[i];
  }

  for (let i = 0; i < items.length; i++) {
    result[start + i] = items[i];
  }

  for (let i = start + deleteCount; i < length; i++) {
    result[start + items.length + i - deleteCount] = this[i];
  }

  this.length = newLength;

  return deletedItems;
};

总结

通过实现这些常见的数组API,我们对数组的底层机制有了更深入的理解。这些API为我们提供了对数组进行操作和处理的强大工具,使我们在JavaScript开发中能够更加灵活地应对各种需求。