Featured image of post JavaScript数据结构与算法 -- 数组篇

JavaScript数据结构与算法 -- 数组篇

最简单的内存数据结构 – 数组

几乎所有的编程语言都原生支持数组类型,数组是最简单的内存数据结构。

数组存储一系列同一种数据类型的值。

一、特点

  • 非固定
  • 非密集型

数组是一种类列表对象,它的原型中提供了遍历和修改元素的相关操作。JavaScript 数组的长度和元素类型都是非固定的。因为数组的长度可随时改变,并且其数据在内存中也可以不连续,所以 JavaScript 数组不一定是密集型的,这取决于它的使用方式。一般来说,数组的这些特性会给使用带来方便,但如果这些特性不适用于你的特定使用场景的话,可以考虑使用类型数组 TypedArray

只能用整数作为数组元素的索引,而不能用字符串。后者称为关联数组。使用非整数并通过方括号点号来访问或设置数组元素时,所操作的并不是数组列表中的元素,而是数组对象的属性集合上的变量。数组对象的属性和数组元素列表是分开存储的,并且数组的遍历和修改操作也不能作用于这些命名属性

二、常见使用场景

需要存储一系列数据,并需要更加简洁地呈现与操作同样的信息时

三、Javascript 中的数组操作

数组的原型(prototype)中提供了遍历和修改元素的相关操作。

创建和初始化

使用中括号 [] 赋值

1
2
3
4
5
6
let arr = [];
let unit = ["nm", "um", "cm", "dm", "m", "km"];
let unit2 = [
  ["nm", "um", "cm", "dm", "m", "km"],
  ["mg", "g", "kg", "t"],
]; // 二维数组

使用 new 关键字。

1
2
3
let arr = new Array();
let arr2 = new Array(7); // 长度为7的空数组
let arr3 = new Array("nm", "um", "cm", "dm", "m", "km");
添加元素
1
2
3
4
5
6
7
// 开头添加
numbers.unshift(-2);
numbers.unshift(-4, -3);

// 结尾添加
numbers.push(11);
numbers.push(12, 13);
删除元素
1
2
numbers.pop(); // 删除最后一个元素
numbers.shift(); // 删除第一个元素
插入或中间删除
1
2
numbers.splice(5, 3); // 删除下标从5开始的3个元素
numbers.splice(5, 0, 2); // 删除下标从5开始的0个元素,并添加一个元素 2

数组方法

方法 介绍 规范
concat 合并数组 ES3
every 对数组中的每个元素运行给定函数,如果该函数对每个元素都返回true ,则返回 true ES5
filter 对数组中的每个元素运行给定函数,返回该函数会返回true 的元素组成的数组 ES5
forEach 对数组中的每个元素运行给定函数。这个方法没有返回值 ES5
join 将所有的数组元素连接成一个字符串 ES3
indexOf 返回第一个与给定参数相等的数组元素的索引,没有找到则返回-1 ES5
lastIndexOf 返回在数组中搜索到的与给定参数相等的元素的索引里最大的值
map 对数组中的每个元素运行给定函数,返回每次函数调用的结果组成的数组
reverse 颠倒数组中元素的顺序,原先第一个元素现在变成最后一个,同样原先的最后一个元素变成了现在的第一个
slice 传入索引值,将数组里对应索引范围内的元素作为新数组返回
some 对数组中的每个元素运行给定函数,如果任一元素返回true ,则返回 true
sort 按照字母顺序对数组排序,支持传入指定排序方法的函数作为参数
toString 将数组作为字符串返回
valueOf toString 类似,将数组作为字符串返回
reduce 方法对数组中的每个元素执行一个由您提供的 reducer 函数(升序执行),将其结果汇总为单个返回值
@@iterator 返回一个包含数组键值对的迭代器对象,可以通过同步调用得到数组元素的键值对 ES6
copyWithin 复制数组中一系列元素到同一数组指定的起始位置 ES6
entries 返回包含数组所有键值对的@@iterator ES6
includes 如果数组中存在某个元素则返回true,否则返回 false ES6
find 根据回调函数给定的条件从数组中查找元素,如果找到则返回该元素 ES6
findIndex 根据回调函数给定的条件从数组中查找元素,如果找到则返回该元素在数组中的索引 ES6
fill 用静态值填充数组 ES6
from 根据已有数组创建一个新数组 ES6
keys 返回包含数组所有索引的@@iterator ES6
of 根据传入的参数创建一个新数组 ES6
values 返回包含数组中所有值的@@iterator ES6
方法说明
  • everysome

every 方法会迭代数组中的每个元素,直到返回 false
someevery的行为相反,会迭代数组的每个元素,直到函数返回 true

1
2
3
var numbers = [1, 2];
numbers.every((nb) => nb % 2 === 0); // 返回数组是否有偶数值
numbers.some((nb) => nb % 2 === 0); // 返回数组是否是有非偶数值
  • forEach

forEach 会迭代整个数组与 for 循环的结果相同。
需要注意,return 是不能跳出forEach循环的

1
2
3
4
var numbers = [1, 2, 3, 4, 5, 6];
numbers.forEach((item) => {
  console.log(item);
});
  • map filter方法

javascript 中返回新数组的迭代方法。
map 返回一个结果数组.
filter 返回一个使函数返回 true 的元素。

1
2
3
4
5
6
let numbers = [1, 2, 10, 12, 14];
let mapBol = numbers.map((mb) => mb > 10);
console.log(mapBol); // [false, false, false, true, ture]

let mapFit = numbers.filter((mb) => mb > 10);
console.log(mapFit); // [12, 14]
  • 使用 reduce 方法

这个函数会返回一个将被叠加到累加器的值,reduce 方法停止执行后会返回这个累加器。

1
numbers.reduce((previous, current) => previous + current); // 求元素和
  • 使用 @@iterator 对象

ES2015 还为 Array 类增加了一个 @@iterator 属性,需要通过 Symbol.iterator 来访问。代码如下。

Symbol 是一种基本数据类型 (primitive data type)。Symbol()函数会返回 symbol 类型的值,该类型具有静态属性和静态方法。

1
2
3
4
let numbers = [1, 2, 3, 4, 5];
let iterator = numbers[Symbol.iterator]();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
  • entrieskeysvalues 方法

ES2015 还增加了三种从数组中得到迭代器的方法。
数组的 entrieskeysvalues 方法

1
2
3
4
5
6
7
let numbers = [1, 2, 3, 4, 5];
const nEntries = numbers.entries();
console.log(aEntries.next().value); // [0, 1] - 位置0的值为1

for (const n of nEntries) {
  console.log(n); // value
}
1
2
const aKeys = numbers.keys(); // 得到数组索引的迭代器
console.log(aKeys.next()); // {value: 0, done: false } keys 的 value 值为下标值
1
2
const aValues = numbers.values(); // 得到数组索引的迭代器
console.log(aValues.next()); // {value: 0, done: false } keys 的 value 值为下标值
  • 使用 from 方法

Array.from 方法根据已有的数组创建一个新数组。比如,要复制 numbers 数组,可以如下这样做。

1
2
3
let numbers2 = Array.from(numbers);
let numbers2 = Array.from(numbers, (x) => x % 2 == 0);
// [false, true, false, true, false]
  • 使用 fill 静态值填充数组。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let numbersCopy = Array.of(1, 2, 3, 4, 5, 6);
numbersCopy.fill(0);
// numbersCopy [0, 0, 0, 0, 0, 0]

let numbersCopy2 = Array.of(1, 2, 3, 4, 5, 6);
numbersCopy2.fill(2, 1);
// numbersCopy2 [1, 2, 2, 2, 2, 2]

let numbersCopy3 = Array.of(1, 2, 3, 4, 5, 6);
numbersCopy3.fill(10, 2, 4);
// numbersCopy2 [1, 2, 10, 10, 5, 6]

fill方法在初始化值的时候非常好用

1
const xLine = Array(10).fill(1);
  • 使用 copyWithin 方法 同数组复制
1
2
3
4
5
6
7
let copyArray = [1, 2, 3, 4, 5, 6];
copyArray.copyWithin(0, 3); // 把下标为3开始的值复制到从0开始之后
// 结果为 [4, 5, 6, 4, 5, 6]

copyArray = [1, 2, 3, 4, 5, 6];
copyArray.copyWithin(1, 3, 5); // 3开始 ~ 5结果 复制到 1
// 结果为 [1, 4, 5, 4, 5, 6]

四、实例展示

  • 九九乘法表
  • 重复像素图
  • 简单数独

五、总结

这里讲解了数组的特点以及javascript中数组的一些使用方法,做为最常用的数据结构,当充分了解数组中的众多方法后,在实际开发的时候可以节省很多时间和代码量,对提高代码质量有显著提升。

六、参考