JavaScript 数据结构与算法中的数组(Array)和列表(List)是两种基本的数据结构,它们在存储和操作数据时起着重要的作用。数组和列表都支持常见的操作,如插入、删除、查找和遍历等,但它们在内存分配、插入删除操作的效率等方面有所不同。了解数组和列表的特性以及它们的适用场景,对于编写高效的 JavaScript 程序以及理解复杂的算法和数据结构都至关重要。

数组

数组的标准定义是:
一个存储元素的线性集合(collection),元素可以通过索引来任意存取,索引通常是数字,用来计算元素之间存储位置的偏移量。

JavaScript 数组用于在单一变量中存储多个值。

  1. 使用数组文本是创建 JavaScript 数组最简单的方法。(推荐)
var array-name = [item1, item2, ...];
var cars = ["Saab", "Volvo", "BMW"];
  1. 使用 JavaScript 关键词 new 创建数组。(不推荐)
var cars = new Array("Saab", "Volvo", "BMW");

push 向数组末尾添加一个或多个元素,并返回新的长度

const arr = [1, 2, 3];
arr.push(4);
// 现在 arr 为 [1, 2, 3, 4]

unshift 向数组的开头添加一个或多个元素,并返回新的长度

const arr = [2, 3];
arr.unshift(1);
// 现在 arr 为 [1, 2, 3]

pop 移除并返回数组的最后一个元素

const arr = [1, 2, 3];
const poppedElement = arr.pop(); // poppedElement = 3
// 现在 arr 为 [1, 2]

shift 移除并返回数组的第一个元素

const arr = [1, 2, 3];
const shiftedElement = arr.shift(); // shiftedElement = 1
// 现在 arr 为 [2, 3]

splice 从数组中添加/删除元素,获得一个新数组

const arr = [1, 2, 3, 4, 5];
arr.splice(2, 1); // 从索引2开始删除1个元素
// 现在 arr 为 [1, 2, 4, 5]
var nums = [1,2,3,7,8,9];
var newElements = [4,5,6];
nums.splice(3,0,newElements);
print(nums); // 1,2,3,4,5,6,7,8,9

slice 返回数组的一部分,不修改原数组

const arr = [1, 2, 3, 4, 5];
const slicedArr = arr.slice(2, 4); // 从索引2到索引4(不包括)的元素
// slicedArr 为 [3, 4], arr 仍为 [1, 2, 3, 4, 5]

concat 将两个或多个数组合并成一个新数组

const arr1 = [1, 2];
const arr2 = [3, 4];
const mergedArr = arr1.concat(arr2);
// mergedArr 为 [1, 2, 3, 4]

every 检测数组中的所有元素是否都符合指定条件

const arr = [1, 2, 3, 4, 5];
// 检查数组中的所有元素是否都大于0
const allGreaterThanZero = arr.every(element => element > 0);
// allGreaterThanZero 为 true,因为所有元素都大于0
// 检查数组中的所有元素是否都是偶数
const allEvenNumbers = arr.every(element => element % 2 === 0);
// allEvenNumbers 为 false,因为数组中有一个奇数(1)

some 测试数组的至少一个元素是否通过了指定函数的测试

const arr = [1, 2, 3];
const hasEven = arr.some(item => item % 2 === 0);
// hasEven 为 true

forEach 遍历数组的每个元素并执行提供的函数

const arr = [1, 2, 3];
arr.forEach(item => {
    console.log(item);
});
// 输出: 1
// 输出: 2
// 输出: 3

map 遍历数组的每个元素并返回一个新数组,新数组的元素由回调函数的返回值组成

const arr = [1, 2, 3];
const doubledArr = arr.map(item => item * 2);
// doubledArr 为 [2, 4, 6]

filter 筛选出数组中满足条件的元素,并将这些元素放入一个新数组中返回

const arr = [1, 2, 3, 4, 5];
// 筛选出数组中的所有偶数
const evenNumbers = arr.filter(element => element % 2 === 0);
// evenNumbers 为 [2, 4]
// 筛选出数组中大于2的元素
const greaterThanTwo = arr.filter(element => element > 2);
// greaterThanTwo 为 [3, 4, 5]

reduce 将数组中的元素通过指定的函数进行累积计算,最终返回一个值

const arr = [1, 2, 3, 4, 5];
// 计算数组中所有元素的和
const sum = arr.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
// sum 为 15 (1 + 2 + 3 + 4 + 5)
// 找出数组中的最大值
const max = arr.reduce((accumulator, currentValue) => Math.max(accumulator, currentValue), arr[0]);
// max 为 5

reduceRight() 类似于 reduce() 方法,但是从数组的末尾开始执行

const arr = ['a', 'b', 'c'];
const reversedStr = arr.reduceRight((accumulator, currentValue) => accumulator + currentValue);
// reversedStr 为 'cba'

for...of 很方便地迭代数组中的元素,而无需手动管理索引

const arr = [1, 2, 3, 4, 5];
for (const element of arr) {
  console.log(element);
}
// 输出: 1 2 3 4 5

@@iterator 返回一个包含数组键值对的迭代器对象,可以通过同步调用得到数组元素的键值对

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let iterator = numbers[Symbol.iterator]()
iterator.next().value // 1
iterator.next().value // 2
iterator.next().value // 3
iterator.next().value // 4
iterator.next().value // 5

entries 返回数组的键值对的迭代器

const arr = ['a', 'b', 'c'];
const entry = arr.entries();
for (const [index, value] of entry) {
    console.log(index, value); // 0 'a', 1 'b', 2 'c'
}

keys 返回数组的索引/键的迭代器

const arr = ['a', 'b', 'c'];
const keys = arr.keys();
for (const key of keys) {
    console.log(key); // 0, 1, 2
}

values 返回数组的值的迭代器

const arr = ['a', 'b', 'c'];
const values = arr.values();
for (const value of values) {
    console.log(value); // 'a', 'b', 'c'
}

from 通过类数组对象或可迭代对象创建一个新的数组实例

const arr = Array.from('hello');
// arr 为 ['h', 'e', 'l', 'l', 'o']

of 一个静态方法,用于创建一个新的数组实例,该数组包含任意数量的参数

const arr = Array.of(1, 2, 3, 4, 5);
// arr 为 [1, 2, 3, 4, 5]
const emptyArray = Array.of();
// emptyArray 为 []

fill 用一个固定值填充数组的所有元素

const arr = [1, 2, 3, 4, 5];
arr.fill(0, 2, 4); // 从索引2开始到索引4之前的位置填充0
// arr 变为 [1, 2, 0, 0, 5]

copyWithin 复制数组的一部分到同一数组中的另一个位置,并返回修改后的数组

// array.copyWithin(target, start, end)
// 目标位置索引 `target`:指的是要复制到的位置。
// 复制的起始位置索引 `start`:指的是要复制的起始位置。
// 复制的结束位置索引 `end`:指的是要复制的结束位置。
var array = [1, 2, 3, 4, 5];
// 将从索引 0 开始的元素复制到索引 3 处,覆盖后面的元素
array.copyWithin(3, 0);
console.log(array); // 输出: [1, 2, 3, 1, 2]
// 目标位置索引是 `3`,表示我们要将复制的元素粘贴到数组中索引为 `3` 的位置。
// 起始位置索引是 `0`,表示我们从数组的开头开始复制元素。
// 没有提供 `end` 参数,因此默认为数组末尾。
const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3, 4); // 从索引3开始复制到索引4之前的位置
// arr 变为 [4, 2, 3, 4, 5]

reverse 反转数组中元素的顺序,修改原数组

const arr = [1, 2, 3, 4, 5];
arr.reverse();
// arr 变为 [5, 4, 3, 2, 1]

sort 对数组元素进行排序,默认按照字符串 Unicode 顺序排序,修改原数组

const arr = [3, 1, 4, 1, 5, 9, 2, 6];
arr.sort((a, b) => a - b); // 数字升序排序
// arr 变为 [1, 1, 2, 3, 4, 5, 6, 9]
var nums = [3,1,2,100,4,200];
nums.sort();
print(nums); // 1,100,2,200,3,4
function compare(num1, num2) {
    return num1 - num2;
}
var nums = [3,1,2,100,4,200];
nums.sort(compare);
print(nums); // 1,2,3,4,100,200

indexOf 在数组中查找指定元素并返回其第一次出现的索引,如果数组中不存在该元素,则返回 -1

const arr = [1, 2, 3, 4, 5];
const index = arr.indexOf(3);
// index 为 2
const notFoundIndex = arr.indexOf(6);
// notFoundIndex 为 -1,因为数组中不存在元素 6
const fromIndex = arr.indexOf(2, 2);
// fromIndex 为 -1,因为从索引 2 开始后面没有元素等于 2

lastIndexOf 从数组的末尾开始搜索指定的元素,并返回它在数组中最后一次出现的索引。如果数组中不存在该元素,则返回 -1

const arr = [1, 2, 3, 4, 3, 2, 1];
const lastIndex = arr.lastIndexOf(3);
// lastIndex 为 4,因为元素 3 在索引 4 处最后一次出现
const notFoundIndex = arr.lastIndexOf(5);
// notFoundIndex 为 -1,因为数组中不存在元素 5
const fromIndex = arr.lastIndexOf(2, 3);
// fromIndex 为 1,因为从索引 3 开始向前搜索,找到元素 2 的最后一次出现在索引 1 处

find 查找数组中第一个满足条件的元素,并返回该元素。如果找到满足条件的元素,则返回该元素;如果找不到,则返回 undefined

const arr = [1, 2, 3, 4, 5];
const found = arr.find(element => element > 2);
// found 为 3,因为 3 是数组中第一个大于 2 的元素
const notFound = arr.find(element => element > 5);
// notFound 为 undefined,因为数组中没有大于 5 的元素

findIndex 返回数组中满足提供的测试函数的第一个元素的索引,否则返回 -1

const arr = [1, 2, 3, 4, 5];
const foundIndex = arr.findIndex(item => item > 3);
// foundIndex 为 3

includes 判断数组是否包含指定的元素,返回布尔值

const arr = [1, 2, 3, 4, 5];
const hasThree = arr.includes(3);
// hasThree 为 true

toString 将数组转换为字符串,返回一个字符串表示数组

const arr = [1, 2, 3];
const str = arr.toString();
// str 为 "1,2,3"

join 将数组中所有元素连接成一个字符串

const arr = [1, 2, 3];
const str = arr.join('-');
// str 为 "1-2-3"

valueOf 和 toString 类似,将数组作为字符串返回

var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May'];
document.getElementById("result").innerHTML = months.valueOf();

flat() 将嵌套数组扁平化为指定深度的新数组

const arr = [1, [2, [3, 4]]];
const flatArr = arr.flat();
// flatArr 为 [1, 2, [3, 4]]

flatMap() 首先使用映射函数映射每个元素,然后将结果扁平化为一个新数组

const arr = [1, 2, 3];
const doubledArr = arr.flatMap(item => [item, item * 2]);
// doubledArr 为 [1, 2, 2, 4, 3, 6]

isArray() 判断给定参数是否为数组

const arr = [1, 2, 3];
const isArray = Array.isArray(arr); // true

列表

列表介绍:

  1. 列表是一组有序的数据、一种线性数据结构
  2. 每个列表中的数据项称为元素
  3. 元素的数量受内存控制(即:元素不是很多)
  4. 不包含任何元素的列表称为空列表
// 创建 List 构造函数
function List() {
  this.listSize = 0 // 列表元素个数
  this.pos = 0 // 列表当前位置
  this.dataStore = [] // 初始化一个空数组用来保存列表元素
  this.clear = clear // 清空列表中的所有元素
  this.find = find // 查找元素
  this.toString = toString // 返回列表字符串形式
  this.insert = insert // 在现有元素后插入新元素
  this.append = append // 在列表元素末尾增加新元素
  this.remove = remove // 从列表中删除元素
  this.front = front // 从列表的当前位置移动到第一元素
  this.end = end // 从列表的当前位置移动到最后一个位置
  this.prev = prev // 将当前位置前移一个位置
  this.next = next // 将当前位置后移一个位置
  this.length = length // 列表包含元素的个数
  this.currPos = currPos // 返回列表当前位置方法
  this.moveTo = moveTo // 将当前位置移动到指定位置
  this.getElement = getElement // 显示当前的元素
  this.contains = contains // 是否包含该元素
}
function append(element) {
  this.dataStore[this.listSize++] = element
}
function find(element) {
  // 此处的++应置于之前 以便返回正确的索引
  for (let i = 0; i < this.dataStore.length; ++i) { // ++i 和 i++ 区别
    if (this.dataStore[i] == element) return i
  }
  return -1
}
function remove(element) {
  const foundAt = this.find(element)
  if (foundAt > -1) {
    this.dataStore.splice(foundAt, 1) // splice 和 slice 区别,各自使用方法
    --this.listSize
    console.log(this.dataStore, this.listSize)
    return
  }
  return false
}
function length() {
  // 列表自己维护的一个变量
  return this.listSize
}
function toString() {
  return this.dataStore
}
function insert(element, afterElemnt) {
  const insertPos = this.find(afterElemnt)
  if (insertPos > -1) {
    this.dataStore.splice(insertPos + 1, 0, element)
    ++this.listSize
    return true
  }
  return false
}
function clear() {
  delete this.dataStore
  this.dataStore = [] // 创建一个空数组 this.dataStore.length = 0 会你报错 this.dataStore是 undefined 的length 不存在
  this.listSize = this.pos = 0
}
function contains(element) {
  for (let i = 0; i < this.dataStore.length; ++i) {
    if (this.dataStore[i] == element) {
      return true
    }
  }
  return false
}
// 遍历列表
function front() {
  this.pos = 0
}
function end() {
  this.pos = this.listSize - 1
}
function prev() {
  if (this.pos > 0) --this.pos
}
function next() {
  if (this.pos < this.listSize) ++this.pos
}
function currPos() {
  return this.pos
}
function moveTo(position) {
  this.pos = position
}
function getElement() {
  return this.dataStore[this.pos]
}

适用场景

数组适用场景

  1. 需要快速访问元素:如果需要通过索引快速访问元素,数组是一个很好的选择。
  2. 固定大小的集合:当需要存储固定数量的元素时,例如存储一组数据的情况,可以使用数组。
  3. 数值计算:数组通常用于存储数值,因为它们支持快速的数值计算和访问。

列表适用场景

  1. 动态数据集合:当需要在运行时动态添加或删除元素时,列表是一个很好的选择。
  2. 数据结构的构建:许多常见的数据结构,如链表、栈和队列,都可以使用列表来实现。
  3. 对元素顺序敏感:如果需要保持元素的插入顺序,并且不关心访问元素的效率,可以使用列表。
  4. 不确定集合大小:当集合的大小不确定或需要频繁的大小变化时,列表比数组更灵活。

最后

脸皮厚的作者想申请一个免费的 star ,请各位领导批准!

请跳转 GitHub 地址,也大家请批评指导!