Movatterモバイル変換


[0]ホーム

URL:


  1. 面向开发者的 Web 技术
  2. JavaScript
  3. JavaScript 指南
  4. 索引集合

此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。

View in EnglishAlways switch to English

索引集合

本章介绍按索引值排序的数据集合。包括数组和类数组结构,如Array 对象和TypedArray 对象。

数组是由名称和索引引用的值构成的有序列表。

例如,考虑一个名为emp 的数组,它包含按数字雇员编号索引的雇员姓名。所以emp[0] 是 0 号员工,emp[1] 是 1 号员工,以此类推。

JavaScript 中没有明确的数组数据类型。但是,你可以使用预定义的Array 对象及其方法来处理应用程序中的数组。Array 对象具有以各种方式操作数组的方法,例如连接、反转和排序。它有一个用于确定数组长度的属性和用于正则表达式的其他属性。

在这篇文章中,我们将专注于数组,但许多相同的概念也适用于类型化数组,因为数组和类型化数组共享许多类似的方法。关于类型化数组的更多信息,请参见类型化数组参考

创建数组

以下语句创建了等效的数组:

js
const arr1 = new Array(element0, element1, /* … ,*/ elementN);const arr2 = Array(element0, element1, /* … ,*/ elementN);const arr3 = [element0, element1, /* … ,*/ elementN];

element0, element1, …, elementN 是数组元素的值列表。当指定这些值时,数组将用它们作为数组的元素初始化。数组的length 属性被设置为参数的数量。

括号语法称为“数组字面量”或“数组初始化式”。它比其他形式的数组创建更短,因此通常是首选。详见数组字面量

为了创建一个长度不为 0,但是又没有任何元素的数组,可选以下任何一种方式:

js
// 这种方式...const arr1 = new Array(arrayLength);// ...与这种方式会形成相同数组const arr2 = Array(arrayLength);// 这个效果也一样const arr3 = [];arr3.length = arrayLength;

备注:以上代码,arrayLength 必须为一个Number。否则,将会创建一个只有单个元素(内含提供的值)的数组。调用arr.length 会返回arrayLength,但数组不包含任何元素。for...in 循环在数组上找不到任何属性。

除了上面所示的新定义的变量外,数组还可以被赋值为新对象或现有对象的属性:

js
const obj = {};// …obj.prop = [element0, element1, /* … ,*/ elementN];// 或const obj = { prop: [element0, element1, /* … ,*/ elementN] };

如果你希望用单个元素初始化一个数组,而这个元素恰好又是Number,那么你必须使用括号语法。当单个Number 传递给Array() 构造函数时,将会被解释为arrayLength,并非单个元素。

js
// 创建一个只有唯一元素的数组:数字 42。const arr = [42];// 创建一个没有元素的数组,且数组的长度被设置成 42。const arr = Array(42);// 上面的代码与下面的代码等价:const arr = [];arr.length = 42;

如果N 不是一个整数,调用Array(N) 将会报RangeError 错误,下面的例子说明了这种行为:

js
const arr = Array(9.3); // RangeError: Invalid array length

如果你需要创建任意类型的单元素数组,安全的方式是使用数组字面量。或者在向数组添加单个元素之前先创建一个空的数组。

你也可以使用Array.of 静态方法来创建包含单个元素的数组。

js
const wisenArray = Array.of(9.3); // wisenArray 只包含一个元素:9.3

引用数组元素

因为元素也是属性,你可以使用属性访问器来访问。假设你定义了以下数组:

js
const myArray = ["Wind", "Rain", "Fire"];

你可以将数组的第一个元素引用为myArray[0],将数组的第二个元素引用为myArray[1],等等...元素的索引从零开始。

备注:你也可以使用属性访问器来访问数组的其他属性,就像对象一样。

js
const arr = ["one", "two", "three"];arr[2]; // threearr["length"]; // 3

填充数组

你可以通过给数组元素赋值来填充数组,例如:

js
const emp = [];emp[0] = "Casey Jones";emp[1] = "Phil Lesh";emp[2] = "August West";

备注:如果你在以上代码中给数组运算符的是一个非整型数值,那么它将作为一个表示数组的对象的属性创建,而不是数组的元素。

js
const arr = [];arr[3.4] = "Oranges";console.log(arr.length); // 0console.log(Object.hasOwn(arr, 3.4)); // true

你也可以在创建数组的时候去填充它:

js
const myArray = new Array("Hello", myVar, 3.14159);// 或const myArray = ["Mango", "Apple", "Orange"];

理解 length

在实现层面,JavaScript 实际上是将元素作为标准的对象属性来存储,把数组索引作为属性名。

length 属性是特殊的,如果存在最后一个元素,则其值总是大于其索引的正整数(在下面的示例中,'Dusty' 的索引是30,所以cats.length 返回30 + 1)。

记住,JavaScript 数组索引是基于 0 的:它们从0 开始,而不是1。这意味着length 属性将比最大的索引值大 1:

js
const cats = [];cats[30] = ["Dusty"];console.log(cats.length); // 31

你也可以给length 属性赋值。

写一个小于数组元素数量的值将截断数组,写0 会彻底清空数组:

js
const cats = ["Dusty", "Misty", "Twiggy"];console.log(cats.length); // 3cats.length = 2;console.log(cats); // [ 'Dusty', 'Misty' ] - Twiggy 已经被移除了cats.length = 0;console.log(cats); // 输出 [],猫名称的数组现在已经空了cats.length = 3;console.log(cats); // 输出 [ <3 empty items> ]

遍历数组

一种常见的操作是遍历数组的值,以某种方式处理每个值。最简单的方法如下:

js
const colors = ["red", "green", "blue"];for (let i = 0; i < colors.length; i++) {  console.log(colors[i]);}

如果你确定数组中没有一个元素求值为false(例如,如果你的数组只包含DOM 节点),你可以选择一个更高效的土法子:

js
const divs = document.getElementsByTagName("div");for (let i = 0, div; (div = divs[i]); i++) {  /* 以某种方式处理 div */}

这避免了检查数组长度的开销,并确保div 变量在每次循环时都被重新赋值给当前项,从而增加了便利性。

forEach() 方法提供了遍历数组元素的其他方法:

js
const colors = ["red", "green", "blue"];colors.forEach((color) => console.log(color));// red// green// blue

传递给forEach 的函数对数组中的每个元素执行一次,数组元素作为参数传递给该函数。未赋值的值不会在forEach 循环迭代。

注意,在数组定义时省略的元素不会在forEach 遍历时被列出,但是手动赋值为undefined 的元素是被列出的:

js
const sparseArray = ["first", "second", , "fourth"];sparseArray.forEach((element) => {  console.log(element);});// first// second// fourthif (sparseArray[2] === undefined) {  console.log("sparseArray[2] 是 undefined"); // true}const nonsparseArray = ["first", "second", undefined, "fourth"];nonsparseArray.forEach((element) => {  console.log(element);});// first// second// undefined// fourth

由于 JavaScript 元素被保存为标准对象属性,因此不建议使用for...in 循环遍历 JavaScript 数组,因为普通元素和所有可枚举属性都将被列出。

数组方法

Array 对象具有下列方法:

concat() 方法连接两个或多个数组并返回一个新的数组。

js
let myArray = ["1", "2", "3"];myArray = myArray.concat("a", "b", "c");// myArray 现在是 ["1", "2", "3", "a", "b", "c"]

join() 方法将数组中的所有元素连接成一个字符串。

js
const myArray = ["Wind", "Rain", "Fire"];const list = myArray.join(" - "); // list 现在是 "Wind - Rain - Fire"

push() 方法在数组末尾添加一个或多个元素,并返回数组操作后的length

js
const myArray = ["1", "2"];myArray.push("3"); // myArray 现在是 ["1", "2", "3"]

pop() 方法从数组移出最后一个元素,并返回该元素。

js
const myArray = ["1", "2", "3"];const last = myArray.pop();// myArray 现在是 ["1", "2"],last 为 "3"

shift() 方法从数组移出第一个元素,并返回该元素。

js
const myArray = ["1", "2", "3"];const first = myArray.shift();// myArray 现在是 ["2", "3"],first 为 "1"

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

js
const myArray = ["1", "2", "3"];myArray.unshift("4", "5");// myArray 变成了 ["4", "5", "1", "2", "3"]

slice() 方法从数组提取一个片段,并作为一个新数组返回。

js
let myArray = ["a", "b", "c", "d", "e"];myArray = myArray.slice(1, 4); // [ "b", "c", "d"]// 从索引 1 开始,提取所有的元素,直到索引 3 为止

at() 方法返回数组中指定索引处的元素,如果索引超出范围,则返回undefined。它主要用于从数组末尾访问元素的负下标。

js
const myArray = ["a", "b", "c", "d", "e"];myArray.at(-2); // "d",myArray 的倒数第二个元素

splice() 方法从数组移除一些元素,并(可选地)替换它们。它返回从数组中删除的元素。

js
const myArray = ["1", "2", "3", "4", "5"];myArray.splice(1, 3, "a", "b", "c", "d");// myArray 现在是 ["1", "a", "b", "c", "d", "5"]// 本代码从 1 号索引开始(或元素“2”所在的位置),// 移除 3 个元素,然后将后续元素插入到那个位置上。

reverse() 方法原地颠倒数组元素的顺序:第一个数组元素变为最后一个数组元素,最后一个数组元素变为第一个数组元素。它返回对数组的引用。

js
const myArray = ["1", "2", "3"];myArray.reverse();// 将原数组颠倒,myArray = [ "3", "2", "1" ]

flat() 方法返回一个新数组,所有子数组元素递归地连接到其中,直到指定的深度。

js
let myArray = [1, 2, [3, 4]];myArray = myArray.flat();// myArray 现在是 [1, 2, 3, 4],因为子数组 [3, 4] 已被展平

sort() 方法对数组的元素进行适当的排序,并返回对数组的引用。

js
const myArray = ["Wind", "Rain", "Fire"];myArray.sort();// 对数组排序,myArray = ["Fire", "Rain", "Wind"]

sort() 也可以接受回调函数来决定如何比较数组元素。使用两个参数调用回调函数,它们是来自数组的两个值。该函数比较这两个值并返回正数、负数或零,表示这两个值的顺序。例如,以下命令将根据字符串的最后一个字母对数组进行排序:

js
const sortFn = (a, b) => {  if (a[a.length - 1] < b[b.length - 1]) {    return -1; // 负数 => a < b,a 在 b 之前  } else if (a[a.length - 1] > b[b.length - 1]) {    return 1; // 正数 => a > b,a 在 b 之后  }  return 0; // 0 => a = b,a 和 b 保持原来的顺序};myArray.sort(sortFn);// 对数组排序,myArray = ["Wind","Fire","Rain"]
  • 如果a 小于b,返回-1(或任何负数)
  • 如果a 大于b,返回1(或任何正数)
  • 如果ab 相等,返回0

indexOf() 方法在数组中搜索searchElement 并返回第一个匹配的索引。

js
const a = ["a", "b", "a", "b", "a"];console.log(a.indexOf("b")); // 1// 再试一次,这次从最后一次匹配之后开始console.log(a.indexOf("b", 2)); // 3console.log(a.indexOf("z")); // -1, 因为找不到 'z'

lastIndexOf() 方法的工作原理类似于indexOf,但这是从末尾开始,反向搜索。

js
const a = ["a", "b", "c", "d", "a", "b"];console.log(a.lastIndexOf("b")); // 5// 再试一次,这次从最后一次匹配之前开始console.log(a.lastIndexOf("b", 4)); // 1console.log(a.lastIndexOf("z")); // -1

forEach() 方法对数组中的每个元素执行callback 并返回undefined

js
const a = ["a", "b", "c"];a.forEach((element) => {  console.log(element);});// 输出:// a// b// c

接受回调的forEach 方法(以及下面的其他方法)被称为迭代方法,因为它们以某种方式遍历整个数组。每个都接受第二个可选的参数thisArg。如果提供,thisArg 将成为回调函数体中this 关键字的值。如果没有提供,就像在明确的对象上下文之外被调用一样,当函数在严格模式下时,thisundefined,当函数在非严格模式下时,this 将引用全局对象(windowglobalThis 等。)。

备注:上面介绍的sort() 方法不是迭代方法,因为它的回调函数只用于比较,不能基于元素顺序以任何特定顺序调用。sort() 也不接受thisArg 形参。

map() 方法返回由每个数组元素上执行callback 的返回值所组成的新数组。

js
const a1 = ["a", "b", "c"];const a2 = a1.map((item) => item.toUpperCase());console.log(a2); // ['A', 'B', 'C']

flatMap() 方法先执行map(),再执行深度为 1 的flat()

js
const a1 = ["a", "b", "c"];const a2 = a1.flatMap((item) => [item.toUpperCase(), item.toLowerCase()]);console.log(a2); // ['A', 'a', 'B', 'b', 'C', 'c']

filter() 方法返回一个新数组,其中包含callback 返回true 的元素。

js
const a1 = ["a", 10, "b", 20, "c", 30];const a2 = a1.filter((item) => typeof item === "number");console.log(a2); // [10, 20, 30]

find() 方法返回callback 返回true 的第一个元素。

js
const a1 = ["a", 10, "b", 20, "c", 30];const i = a1.find((item) => typeof item === "number");console.log(i); // 10

findLast() 方法返回callback 返回true 的最后一个元素。

js
const a1 = ["a", 10, "b", 20, "c", 30];const i = a1.findLast((item) => typeof item === "number");console.log(i); // 30

findIndex() 方法返回callback 返回true 的第一个元素的索引。

js
const a1 = ["a", 10, "b", 20, "c", 30];const i = a1.findIndex((item) => typeof item === "number");console.log(i); // 1

findLastIndex() 方法返回callback 返回true 的最后一个元素的索引。

js
const a1 = ["a", 10, "b", 20, "c", 30];const i = a1.findLastIndex((item) => typeof item === "number");console.log(i); // 5

如果callback 对数组中的每一个元素都返回true,则every() 方法返回true

js
function isNumber(value) {  return typeof value === "number";}const a1 = [1, 2, 3];console.log(a1.every(isNumber)); // trueconst a2 = [1, "2", 3];console.log(a2.every(isNumber)); // false

如果callback 对数组中至少一个元素返回true,则some() 方法返回true

js
function isNumber(value) {  return typeof value === "number";}const a1 = [1, 2, 3];console.log(a1.some(isNumber)); // trueconst a2 = [1, "2", 3];console.log(a2.some(isNumber)); // trueconst a3 = ["1", "2", "3"];console.log(a3.some(isNumber)); // false

reduce() 方法对数组中的每个值执行callback(accumulator, currentValue, currentIndex, Array),目的是将列表中的元素减少到单个值。reduce 函数返回callback 函数返回的最终值。

如果指定了initialValue,则调用callback,并将initialValue 作为第一个参数值,将数组中第一个元素的值作为第二个参数值。

如果没有指定initialValue,那么callback 的前两个参数值将是数组的第一个和第二个元素。之后的每一次调用,第一个参数的值将是前一个调用中返回的callback,第二个参数的值将是数组中的下一个值。

如果callback 需要访问正在处理的元素的索引,或者访问整个数组,它们可以作为可选参数。

js
const a = [10, 20, 30];const total = a.reduce(  (accumulator, currentValue) => accumulator + currentValue,  0,);console.log(total); // 60

reduceRight() 方法的工作原理类似于reduce(),但从最后一个元素开始。

reducereduceRight 是迭代数组方法中最不被人熟知的两个函数。它们应该使用在那些需要把数组的元素两两递归处理,并最终计算成一个单一结果的算法。

稀疏数组

数组可以包含“空槽”,这与用值undefined 填充的槽不一样。空槽可以通过以下方式之一创建:

js
// Array 构造函数:const a = Array(5); // [ <5 empty items> ]// 数组字面量中的连续逗号:const b = [1, 2, , , 5]; // [ 1, 2, <2 empty items>, 5 ]// 直接给大于 array.length 的索引设置值以形成空槽:const c = [1, 2];c[4] = 5; // [ 1, 2, <2 empty items>, 5 ]// 通过直接设置 .length 拉长一个数组:const d = [1, 2];d.length = 5; // [ 1, 2, <3 empty items> ]// 删除一个元素:const e = [1, 2, 3, 4, 5];delete e[2]; // [ 1, 2, <1 empty item>, 4, 5 ]

在某些操作中,空槽的行为就像它们被填入了undefined 那样。

js
const arr = [1, 2, , , 5]; // 创建一个稀疏数组// 通过索引访问console.log(arr[2]); // undefined// For...offor (const i of arr) {  console.log(i);}// 输出:1 2 undefined undefined 5// 展开运算const another = [...arr]; // "another" 为 [ 1, 2, undefined, undefined, 5 ]

在其他方法,特别是数组迭代方法时,空槽是被跳过的。

js
const mapped = arr.map((i) => i + 1); // [ 2, 3, <2 empty items>, 6 ]arr.forEach((i) => console.log(i)); // 1 2 5const filtered = arr.filter(() => true); // [ 1, 2, 5 ]const hasFalsy = arr.some((k) => !k); // false// 属性迭代const keys = Object.keys(arr); // [ '0', '1', '4' ]for (const key in arr) {  console.log(key);}// 输出:'0' '1' '4'// 在对象中使用展开,使用属性枚举,而不是数组的迭代器const objectSpread = { ...arr }; // { '0': 1, '1': 2, '4': 5 }

关于数组方法在稀疏数组中的行为的完整列表,请参见Array 参考页

多维数组

数组是可以嵌套的,这就意味着一个数组可以作为一个元素被包含在另外一个数组里面。利用 JavaScript 数组的这个特性,可以创建多维数组。

以下代码创建了一个二维数组。

js
const a = new Array(4);for (i = 0; i < 4; i++) {  a[i] = new Array(4);  for (j = 0; j < 4; j++) {    a[i][j] = "[" + i + "," + j + "]";  }}

这个例子创建的数组拥有以下行数据:

Row 0: [0,0] [0,1] [0,2] [0,3]Row 1: [1,0] [1,1] [1,2] [1,3]Row 2: [2,0] [2,1] [2,2] [2,3]Row 3: [3,0] [3,1] [3,2] [3,3]

使用数组存储其他属性

数组也可以像对象那样使用,以存储相关信息:

js
const arr = [1, 2, 3];arr.property = "value";console.log(arr.property); // "value"

例如,当一个数组作为字符串和正则表达式的匹配结果时,该数组将会返回相关匹配信息的属性和元素。RegExp.prototype.exec()String.prototype.match()String.prototype.split() 的返回值是一个数组。使用数组和正则表达式的更多信息,参见正则表达式

使用类数组对象

一些 JavaScript 对象,如document.getElementsByTagName() 返回的NodeListarguments 等 JavaScript 对象,有与数组相似的行为,但它们并不共享数组的所有方法。arguments 对象提供了length 属性,但没有实现如forEach() 等数组方法。

不能直接在类数组对象上调用数组方法。

js
function printArguments() {  arguments.forEach((item) => {    console.log(item);  }); // TypeError: arguments.forEach is not a function}

但你可以通过Function.prototype.call() 间接调用它们。

js
function printArguments() {  Array.prototype.forEach.call(arguments, (item) => {    console.log(item);  });}

数组原型方法也可以用于字符串,因为它们以类似于数组的方式提供对其中字符的顺序访问:

js
Array.prototype.forEach.call("a string", (chr) => {  console.log(chr);});

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp