返回

手写 JS 数组内置方法,认识 ADT 的实现原理-JavaScript 学习数据结构

前端

数组是我们在编程中使用最为频繁的数据结构,很多时候,基础知识书籍和文章通常直接忽略掉数组的部分,尤其是数组的抽象数据类型(ADT)实现原理介绍。毕竟,现代的绝大多数编程语言中,都内置了很多关于数组的操作方法,我们仅需按照编程语言的规范来使用和调用这些方法,就可以轻松地实现数组的增删改查等基本操作。

那么,这些内置数组方法是如何实现的呢?它们是如何基于 JavaScript 语言的语法和机制,来构建出这样一个功能强大的、ADT 抽象数据结构的呢?

在这篇文章中,我们将一起手写一些 JavaScript 数组的内置方法,并尝试理解它们的实现原理。在这个过程中,我们不仅可以加深对数组的理解,还可以对抽象数据类型 (ADT) 有更深入的认识。

手写 JavaScript 数组内置方法

1. Array.push() 方法

Array.push() 方法用于向数组的末尾添加一个或多个元素,并返回新的数组长度。

Array.prototype.push = function () {
  for (let i = 0; i < arguments.length; i++) {
    this[this.length] = arguments[i];
  }
  return this.length;
};

2. Array.pop() 方法

Array.pop() 方法用于移除数组的最后一个元素,并返回该元素。

Array.prototype.pop = function () {
  if (this.length === 0) {
    return undefined;
  }
  const lastElement = this[this.length - 1];
  delete this[this.length - 1];
  this.length--;
  return lastElement;
};

3. Array.shift() 方法

Array.shift() 方法用于移除数组的第一个元素,并返回该元素。

Array.prototype.shift = function () {
  if (this.length === 0) {
    return undefined;
  }
  const firstElement = this[0];
  for (let i = 1; i < this.length; i++) {
    this[i - 1] = this[i];
  }
  delete this[this.length - 1];
  this.length--;
  return firstElement;
};

4. Array.unshift() 方法

Array.unshift() 方法用于向数组的开头添加一个或多个元素,并返回新的数组长度。

Array.prototype.unshift = function () {
  for (let i = this.length; i >= 0; i--) {
    this[i + arguments.length] = this[i];
  }
  for (let i = 0; i < arguments.length; i++) {
    this[i] = arguments[i];
  }
  return this.length;
};

5. Array.slice() 方法

Array.slice() 方法用于创建一个新数组,它是原数组的指定范围内的浅拷贝。

Array.prototype.slice = function (start, end) {
  if (start < 0) {
    start = this.length + start;
  }
  if (end < 0) {
    end = this.length + end;
  }
  if (start > end) {
    return [];
  }
  const newLength = Math.min(end, this.length) - start;
  const newArray = new Array(newLength);
  for (let i = 0; i < newLength; i++) {
    newArray[i] = this[start + i];
  }
  return newArray;
};

6. Array.splice() 方法

Array.splice() 方法用于向数组的指定位置添加或移除元素,并返回被移除的元素。

Array.prototype.splice = function (start, deleteCount, ...items) {
  if (start < 0) {
    start = this.length + start;
  }
  if (deleteCount < 0) {
    deleteCount = 0;
  }
  if (start > this.length) {
    return [];
  }
  const removedItems = this.slice(start, start + deleteCount);
  const newLength = this.length - deleteCount + items.length;
  this.length = newLength;
  for (let i = this.length - 1; i >= start + items.length; i--) {
    this[i] = this[i - items.length];
  }
  for (let i = start; i < start + items.length; i++) {
    this[i] = items[i - start];
  }
  return removedItems;
};

理解 ADT 的实现原理

通过手写 JavaScript 数组内置方法,我们可以对抽象数据类型 (ADT) 的实现原理有更深入的认识。ADT 是计算机科学中的一种数据类型,它定义了数据结构的接口和操作,而具体的实现细节则可以隐藏起来。

在 JavaScript 中,数组是 ADT 的一个典型例子。数组的接口定义了我们可以在数组上执行的操作,例如 push、pop、shift、unshift、slice、splice 等。这些操作的实现细节则隐藏在数组的内部。

ADT 的实现原理是使用一种称为“封装”的技术。封装是指将数据和操作封装在一个单元中,从而隐藏数据和操作的实现细节。在 JavaScript 中,数组的封装是通过使用对象来实现的。

数组对象包含一个称为“length”的属性,该属性表示数组的长度。数组对象还包含一个称为“[]”的索引属性,该属性可以用来访问数组中的元素。

数组对象的封装使得我们可以像操作简单对象一样来操作数组。例如,我们可以使用“[]”索引属性来访问数组中的元素,也可以使用“length”属性来获取数组的长度。

结语

通过手写 JavaScript 数组内置方法,我们不仅可以加深对数组的理解,还可以对抽象数据类型 (ADT) 的实现原理有更深入的认识。ADT 是计算机科学中的一种重要概念,它可以帮助我们更好地理解和设计数据结构。