索引集合

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

¥This chapter introduces collections of data which are ordered by an index value. This includes arrays and array-like constructs such as Array objects and TypedArray objects.

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

¥An array is an ordered list of values that you refer to with a name and an index.

例如,考虑一个名为 emp 的数组,其中包含按员工编号索引的员工名称。因此 emp[0] 是零号员工,emp[1] 是一号员工,依此类推。

¥For example, consider an array called emp, which contains employees' names indexed by their numerical employee number. So emp[0] would be employee number zero, emp[1] employee number one, and so on.

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

¥JavaScript does not have an explicit array data type. However, you can use the predefined Array object and its methods to work with arrays in your applications. The Array object has methods for manipulating arrays in various ways, such as joining, reversing, and sorting them. It has a property for determining the array length and other properties for use with regular expressions.

我们将在本文中重点讨论数组,但许多相同的概念也适用于类型化数组,因为数组和类型化数组共享许多相似的方法。有关类型化数组的更多信息,请参阅 类型化数组指南

¥We will be focusing on arrays in this article, but many of the same concepts apply to typed arrays as well, since arrays and typed arrays share many similar methods. For more information on typed arrays, see the typed array guide.

创建数组

¥Creating an array

以下语句创建等效数组:

¥The following statements create equivalent arrays:

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

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

¥element0, element1, …, elementN is a list of values for the array's elements. When these values are specified, the array is initialized with them as the array's elements. The array's length property is set to the number of arguments.

括号语法称为 "数组字面量" 或 "数组初始值设定项。" 它比其他形式的数组创建更短,因此通常是首选。详情请参见 数组文字

¥The bracket syntax is called an "array literal" or "array initializer." It's shorter than other forms of array creation, and so is generally preferred. See Array literals for details.

要创建长度非零但不包含任何项目的数组,可以使用以下任一方法:

¥To create an array with non-zero length, but without any items, either of the following can be used:

js
// This...
const arr1 = new Array(arrayLength);

// ...results in the same array as this
const arr2 = Array(arrayLength);

// This has exactly the same effect
const arr3 = [];
arr3.length = arrayLength;

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

¥Note: In the above code, arrayLength must be a Number. Otherwise, an array with a single element (the provided value) will be created. Calling arr.length will return arrayLength, but the array doesn't contain any elements. A for...in loop will not find any property on the array.

除了如上所示的新定义的变量之外,还可以将数组指定为新对象或现有对象的属性:

¥In addition to a newly defined variable as shown above, arrays can also be assigned as a property of a new or an existing object:

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

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

如果你希望用单个元素初始化数组,并且该元素恰好是 Number,则必须使用括号语法。当单个 Number 值传递给 Array() 构造函数或函数时,它被解释为 arrayLength,而不是单个元素。

¥If you wish to initialize an array with a single element, and the element happens to be a Number, you must use the bracket syntax. When a single Number value is passed to the Array() constructor or function, it is interpreted as an arrayLength, not as a single element.

这将创建一个只有一个元素的数组:42 号。

¥This creates an array with only one element: the number 42.

js
const arr = [42];

这将创建一个没有元素的数组,并且 arr.length 设置为 42。

¥This creates an array with no elements and arr.length set to 42.

js
const arr = Array(42);

这相当于:

¥This is equivalent to:

js
const arr = [];
arr.length = 42;

如果 N 是小数部分非零的非整数,则调用 Array(N) 会产生 RangeError。以下示例说明了此行为。

¥Calling Array(N) results in a RangeError, if N is a non-whole number whose fractional portion is non-zero. The following example illustrates this behavior.

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

如果你的代码需要创建具有任意数据类型的单个元素的数组,那么使用数组文字会更安全。或者,先创建一个空数组,然后再向其中添加单个元素。

¥If your code needs to create arrays with single elements of an arbitrary data type, it is safer to use array literals. Alternatively, create an empty array first before adding the single element to it.

你还可以使用 Array.of 静态方法创建具有单个元素的数组。

¥You can also use the Array.of static method to create arrays with single element.

js
const wisenArray = Array.of(9.3); // wisenArray contains only one element 9.3

引用数组元素

¥Referring to array elements

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

¥Because elements are also properties, you can access them using property accessors. Suppose you define the following array:

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

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

¥You can refer to the first element of the array as myArray[0], the second element of the array as myArray[1], etc… The index of the elements begins with zero.

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

¥Note: You can also use property accessors to access other properties of the array, like with an object.

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

填充数组

¥Populating an array

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

¥You can populate an array by assigning values to its elements. For example:

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

注意:如果在上面的代码中向数组运算符提供非整数值,则将在表示数组的对象中创建一个属性,而不是数组元素。

¥Note: If you supply a non-integer value to the array operator in the code above, a property will be created in the object representing the array, instead of an array element.

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

你还可以在创建数组时填充数组:

¥You can also populate an array when you create it:

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

了解长度

¥Understanding length

在实现级别,JavaScript 的数组实际上将其元素存储为标准对象属性,并使用数组索引作为属性名称。

¥At the implementation level, JavaScript's arrays actually store their elements as standard object properties, using the array index as the property name.

length 属性很特殊。它的值始终是一个大于最后一个元素的索引(如果存在)的正整数。(在下面的示例中,'Dusty'30 处索引,因此 cats.length 返回 30 + 1)。

¥The length property is special. Its value is always a positive integer greater than the index of the last element if one exists. (In the example below, 'Dusty' is indexed at 30, so cats.length returns 30 + 1).

请记住,JavaScript 数组索引是从 0 开始的:他们从 0 开始,而不是 1。这意味着 length 属性将比数组中存储的最高索引多 1:

¥Remember, JavaScript Array indexes are 0-based: they start at 0, not 1. This means that the length property will be one more than the highest index stored in the array:

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

你还可以分配给 length 属性。

¥You can also assign to the length property.

写入比存储项数短的值会截断数组。写入 0 将其完全清空:

¥Writing a value that is shorter than the number of stored items truncates the array. Writing 0 empties it entirely:

js
const cats = ["Dusty", "Misty", "Twiggy"];
console.log(cats.length); // 3

cats.length = 2;
console.log(cats); // [ 'Dusty', 'Misty' ] - Twiggy has been removed

cats.length = 0;
console.log(cats); // []; the cats array is empty

cats.length = 3;
console.log(cats); // [ <3 empty items> ]

迭代数组

¥Iterating over arrays

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

¥A common operation is to iterate over the values of an array, processing each one in some way. The simplest way to do this is as follows:

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

如果你知道数组中没有任何元素在布尔上下文中计算结果为 false(例如,如果你的数组仅包含 DOM 个节点),你可以使用更有效的习惯用法:

¥If you know that none of the elements in your array evaluate to false in a boolean context—if your array consists only of DOM nodes, for example—you can use a more efficient idiom:

js
const divs = document.getElementsByTagName("div");
for (let i = 0, div; (div = divs[i]); i++) {
  /* Process div in some way */
}

这避免了检查数组长度的开销,并确保每次循环时都将 div 变量重新分配给当前项,以增加便利性。

¥This avoids the overhead of checking the length of the array, and ensures that the div variable is reassigned to the current item each time around the loop for added convenience.

forEach() 方法提供了另一种迭代数组的方法:

¥The forEach() method provides another way of iterating over an array:

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

传递给 forEach 的函数对数组中的每个项目执行一次,并将数组项目作为参数传递给函数。未分配的值不会在 forEach 循环中迭代。

¥The function passed to forEach is executed once for every item in the array, with the array item passed as the argument to the function. Unassigned values are not iterated in a forEach loop.

请注意,定义数组时省略的数组元素在按 forEach 迭代时不会列出,但在手动将 undefined 分配给元素时列出:

¥Note that the elements of an array that are omitted when the array is defined are not listed when iterating by forEach, but are listed when undefined has been manually assigned to the element:

js
const sparseArray = ["first", "second", , "fourth"];

sparseArray.forEach((element) => {
  console.log(element);
});
// Logs:
// first
// second
// fourth

if (sparseArray[2] === undefined) {
  console.log("sparseArray[2] is undefined"); // true
}

const nonsparseArray = ["first", "second", undefined, "fourth"];

nonsparseArray.forEach((element) => {
  console.log(element);
});
// Logs:
// first
// second
// undefined
// fourth

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

¥Since JavaScript array elements are saved as standard object properties, it is not advisable to iterate through JavaScript arrays using for...in loops, because normal elements and all enumerable properties will be listed.

数组方法

¥Array methods

Array 对象有以下方法:

¥The Array object has the following methods:

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

¥The concat() method joins two or more arrays and returns a new array.

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

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

¥The join() method joins all elements of an array into a string.

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

push() 方法将一个或多个元素添加到数组末尾并返回数组的结果 length

¥The push() method adds one or more elements to the end of an array and returns the resulting length of the array.

js
const myArray = ["1", "2"];
myArray.push("3"); // myArray is now ["1", "2", "3"]

pop() 方法从数组中删除最后一个元素并返回该元素。

¥The pop() method removes the last element from an array and returns that element.

js
const myArray = ["1", "2", "3"];
const last = myArray.pop();
// myArray is now ["1", "2"], last = "3"

shift() 方法从数组中删除第一个元素并返回该元素。

¥The shift() method removes the first element from an array and returns that element.

js
const myArray = ["1", "2", "3"];
const first = myArray.shift();
// myArray is now ["2", "3"], first is "1"

unshift() 方法将一个或多个元素添加到数组的前面并返回数组的新长度。

¥The unshift() method adds one or more elements to the front of an array and returns the new length of the array.

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

slice() 方法提取数组的一部分并返回一个新数组。

¥The slice() method extracts a section of an array and returns a new array.

js
let myArray = ["a", "b", "c", "d", "e"];
myArray = myArray.slice(1, 4); // [ "b", "c", "d"]
// starts at index 1 and extracts all elements
// until index 3

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

¥The at() method returns the element at the specified index in the array, or undefined if the index is out of range. It's notably used for negative indices that access elements from the end of the array.

js
const myArray = ["a", "b", "c", "d", "e"];
myArray.at(-2); // "d", the second-last element of myArray

splice() 方法从数组中删除元素并(可选)替换它们。它返回从数组中删除的项目。

¥The splice() method removes elements from an array and (optionally) replaces them. It returns the items which were removed from the array.

js
const myArray = ["1", "2", "3", "4", "5"];
myArray.splice(1, 3, "a", "b", "c", "d");
// myArray is now ["1", "a", "b", "c", "d", "5"]
// This code started at index one (or where the "2" was),
// removed 3 elements there, and then inserted all consecutive
// elements in its place.

reverse() 方法就地转置数组的元素:第一个数组元素成为最后一个元素,最后一个元素成为第一个元素。它返回对数组的引用。

¥The reverse() method transposes the elements of an array, in place: the first array element becomes the last and the last becomes the first. It returns a reference to the array.

js
const myArray = ["1", "2", "3"];
myArray.reverse();
// transposes the array so that myArray = ["3", "2", "1"]

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

¥The flat() method returns a new array with all sub-array elements concatenated into it recursively up to the specified depth.

js
let myArray = [1, 2, [3, 4]];
myArray = myArray.flat();
// myArray is now [1, 2, 3, 4], since the [3, 4] subarray is flattened

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

¥The sort() method sorts the elements of an array in place, and returns a reference to the array.

js
const myArray = ["Wind", "Rain", "Fire"];
myArray.sort();
// sorts the array so that myArray = ["Fire", "Rain", "Wind"]

sort() 还可以采用回调函数来确定如何比较数组元素。使用两个参数调用回调函数,这两个参数是数组中的两个值。该函数比较这两个值并返回正数、负数或零,指示两个值的顺序。例如,以下代码将按字符串的最后一个字母对数组进行排序:

¥sort() can also take a callback function to determine how array elements are compared. The callback function is called with two arguments, which are two values from the array. The function compares these two values and returns a positive number, negative number, or zero, indicating the order of the two values. For instance, the following will sort the array by the last letter of a string:

js
const sortFn = (a, b) => {
  if (a[a.length - 1] < b[b.length - 1]) {
    return -1; // Negative number => a < b, a comes before b
  } else if (a[a.length - 1] > b[b.length - 1]) {
    return 1; // Positive number => a > b, a comes after b
  }
  return 0; // Zero => a = b, a and b keep their original order
};
myArray.sort(sortFn);
// sorts the array so that myArray = ["Wind","Fire","Rain"]
  • 如果排序系统判断 a 小于 b,则返回 -1(或任何负数)
  • 如果排序系统判断 a 大于 b,则返回 1(或任何正数)
  • 如果 ab 被认为是等价的,则返回 0

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

¥The indexOf() method searches the array for searchElement and returns the index of the first match.

js
const a = ["a", "b", "a", "b", "a"];
console.log(a.indexOf("b")); // 1

// Now try again, starting from after the last match
console.log(a.indexOf("b", 2)); // 3
console.log(a.indexOf("z")); // -1, because 'z' was not found

lastIndexOf() 方法的工作方式与 indexOf 类似,但从末尾开始向后搜索。

¥The lastIndexOf() method works like indexOf, but starts at the end and searches backwards.

js
const a = ["a", "b", "c", "d", "a", "b"];
console.log(a.lastIndexOf("b")); // 5

// Now try again, starting from before the last match
console.log(a.lastIndexOf("b", 4)); // 1
console.log(a.lastIndexOf("z")); // -1

forEach() 方法对每个数组项执行 callback 并返回 undefined

¥The forEach() method executes callback on every array item and returns undefined.

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

接受回调的 forEach 方法(以及下面的其他方法)被称为迭代方法,因为它们以某种方式迭代整个数组。每个参数都带有一个可选的第二个参数,称为 thisArg。如果提供,thisArg 将成为回调函数体内 this 关键字的值。如果未提供,与在显式对象上下文之外调用函数的其他情况一样,当函数为 不严格 时,this 将引用全局对象(windowglobalThis 等),当函数为严格时,undefined 将引用全局对象。

¥The forEach method (and others below) that take a callback are known as iterative methods, because they iterate over the entire array in some fashion. Each one takes an optional second argument called thisArg. If provided, thisArg becomes the value of the this keyword inside the body of the callback function. If not provided, as with other cases where a function is invoked outside of an explicit object context, this will refer to the global object (window, globalThis, etc.) when the function is not strict, or undefined when the function is strict.

注意:上面介绍的 sort() 方法不是迭代方法,因为它的回调函数仅用于比较,并且可能不会根据元素顺序以任何特定顺序调用。sort() 也不接受 thisArg 参数。

¥Note: The sort() method introduced above is not an iterative method, because its callback function is only used for comparison and may not be called in any particular order based on element order. sort() does not accept the thisArg parameter either.

map() 方法返回一个新数组,其中包含对每个数组项执行 callback 的返回值。

¥The map() method returns a new array of the return value from executing callback on every array item.

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

flatMap() 方法运行 map(),然后运行深度为 1 的 flat()

¥The flatMap() method runs map() followed by a flat() of depth 1.

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 的项目。

¥The filter() method returns a new array containing the items for which callback returned 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 的第一个项目。

¥The find() method returns the first item for which callback returned 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 的最后一项。

¥The findLast() method returns the last item for which callback returned 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 的第一个项目的索引。

¥The findIndex() method returns the index of the first item for which callback returned 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 的最后一项的索引。

¥The findLastIndex() method returns the index of the last item for which callback returned 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

¥The every() method returns true if callback returns true for every item in the array.

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

如果 callback 对于数组中的至少一项返回 true,则 some() 方法将返回 true

¥The some() method returns true if callback returns true for at least one item in the array.

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

reduce() 方法对数组中的每个值应用 callback(accumulator, currentValue, currentIndex, array),以便将项目列表缩减为单个值。reduce 函数返回 callback 函数返回的最终值。

¥The reduce() method applies callback(accumulator, currentValue, currentIndex, array) for each value in the array for the purpose of reducing the list of items down to a single value. The reduce function returns the final value returned by callback function.

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

¥If initialValue is specified, then callback is called with initialValue as the first parameter value and the value of the first item in the array as the second parameter value.

如果未指定 initialValue,则 callback 的前两个参数值将是数组的第一个和第二个元素。在每次后续调用中,第一个参数的值将是上次调用时 callback 返回的值,第二个参数的值将是数组中的下一个值。

¥If initialValue is not specified, then callback's first two parameter values will be the first and second elements of the array. On every subsequent call, the first parameter's value will be whatever callback returned on the previous call, and the second parameter's value will be the next value in the array.

如果 callback 需要访问正在处理的项目的索引,或访问整个数组,则它们可以作为可选参数使用。

¥If callback needs access to the index of the item being processed, or access to the entire array, they are available as optional parameters.

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

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

¥The reduceRight() method works like reduce(), but starts with the last element.

reducereduceRight 是迭代数组方法中最不明显的。它们应该用于递归地组合两个值的算法,以便将序列减少到单个值。

¥reduce and reduceRight are the least obvious of the iterative array methods. They should be used for algorithms that combine two values recursively in order to reduce a sequence down to a single value.

数组转换

¥Array transformations

你可以在数组和其他数据结构之间来回转换。

¥You can transform back and forth between arrays and other data structures.

对数组的元素进行分组

¥Grouping the elements of an array

Object.groupBy() 方法可用于对数组的元素进行分组,使用返回指示当前元素组的字符串的测试函数。

¥The Object.groupBy() method can be used to group the elements of an array, using a test function that returns a string indicating the group of the current element.

这里我们有一个简单的库存数组,其中包含 "food" 对象,这些对象具有 nametype

¥Here we have a simple inventory array that contains "food" objects that have a name and a type.

js
const inventory = [
  { name: "asparagus", type: "vegetables" },
  { name: "bananas", type: "fruit" },
  { name: "goat", type: "meat" },
  { name: "cherries", type: "fruit" },
  { name: "fish", type: "meat" },
];

要使用 Object.groupBy(),你需要提供一个使用当前元素以及可选的当前索引和数组调用的回调函数,并返回一个指示元素组的字符串。

¥To use Object.groupBy(), you supply a callback function that is called with the current element, and optionally the current index and array, and returns a string indicating the group of the element.

下面的代码使用箭头函数返回每个数组元素的 type(这使用 函数参数的对象解构语法 从传递的对象中解压 type 元素)。结果是一个对象,该对象具有以回调返回的唯一字符串命名的属性。每个属性都分配有一个包含组中元素的数组。

¥The code below uses an arrow function to return the type of each array element (this uses object destructuring syntax for function arguments to unpack the type element from the passed object). The result is an object that has properties named after the unique strings returned by the callback. Each property is assigned an array containing the elements in the group.

js
const result = Object.groupBy(inventory, ({ type }) => type);
console.log(result);
// Logs
// {
//   vegetables: [{ name: 'asparagus', type: 'vegetables' }],
//   fruit: [
//     { name: 'bananas', type: 'fruit' },
//     { name: 'cherries', type: 'fruit' }
//   ],
//   meat: [
//     { name: 'goat', type: 'meat' },
//     { name: 'fish', type: 'meat' }
//   ]
// }

请注意,返回的对象引用与原始数组相同的元素(不是 deep copies)。更改这些元素的内部结构将反映在原始数组和返回的对象中。

¥Note that the returned object references the same elements as the original array (not deep copies). Changing the internal structure of these elements will be reflected in both the original array and the returned object.

如果你无法使用字符串作为键,例如,如果要分组的信息与可能更改的对象关联,那么你可以改用 Map.groupBy()。这与 Object.groupBy() 非常相似,只不过它将数组的元素分组为 Map,可以使用任意值(objectprimitive)作为键。

¥If you can't use a string as the key, for example, if the information to group is associated with an object that might change, then you can instead use Map.groupBy(). This is very similar to Object.groupBy() except that it groups the elements of the array into a Map that can use an arbitrary value (object or primitive) as a key.

稀疏数组

¥Sparse arrays

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

¥Arrays can contain "empty slots", which are not the same as slots filled with the value undefined. Empty slots can be created in one of the following ways:

js
// Array constructor:
const a = Array(5); // [ <5 empty items> ]

// Consecutive commas in array literal:
const b = [1, 2, , , 5]; // [ 1, 2, <2 empty items>, 5 ]

// Directly setting a slot with index greater than array.length:
const c = [1, 2];
c[4] = 5; // [ 1, 2, <2 empty items>, 5 ]

// Elongating an array by directly setting .length:
const d = [1, 2];
d.length = 5; // [ 1, 2, <3 empty items> ]

// Deleting an element:
const e = [1, 2, 3, 4, 5];
delete e[2]; // [ 1, 2, <1 empty item>, 4, 5 ]

在某些操作中,空槽的行为就像用 undefined 填充一样。

¥In some operations, empty slots behave as if they are filled with undefined.

js
const arr = [1, 2, , , 5]; // Create a sparse array

// Indexed access
console.log(arr[2]); // undefined

// For...of
for (const i of arr) {
  console.log(i);
}
// Logs: 1 2 undefined undefined 5

// Spreading
const another = [...arr]; // "another" is [ 1, 2, undefined, undefined, 5 ]

但在其他方法中(最明显的是数组迭代方法),会跳过空槽。

¥But in others (most notably array iteration methods), empty slots are skipped.

js
const mapped = arr.map((i) => i + 1); // [ 2, 3, <2 empty items>, 6 ]
arr.forEach((i) => console.log(i)); // 1 2 5
const filtered = arr.filter(() => true); // [ 1, 2, 5 ]
const hasFalsy = arr.some((k) => !k); // false

// Property enumeration
const keys = Object.keys(arr); // [ '0', '1', '4' ]
for (const key in arr) {
  console.log(key);
}
// Logs: '0' '1' '4'
// Spreading into an object uses property enumeration, not the array's iterator
const objectSpread = { ...arr }; // { '0': 1, '1': 2, '4': 5 }

有关数组方法如何处理稀疏数组的完整列表,请参阅 Array 参考页

¥For a complete list of how array methods behave with sparse arrays, see the Array reference page.

多维数组

¥Multi-dimensional arrays

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

¥Arrays can be nested, meaning that an array can contain another array as an element. Using this characteristic of JavaScript arrays, multi-dimensional arrays can be created.

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

¥The following code creates a two-dimensional array.

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

此示例创建一个包含以下行的数组:

¥This example creates an array with the following rows:

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]

使用数组来存储其他属性

¥Using arrays to store other properties

数组也可以像对象一样使用,来存储相关信息。

¥Arrays can also be used like objects, to store related information.

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

例如,当数组是正则表达式和字符串之间的匹配结果时,该数组将返回提供有关匹配信息的属性和元素。数组是 RegExp.prototype.exec()String.prototype.match()String.prototype.split() 的返回值。有关将数组与正则表达式一起使用的信息,请参阅 正则表达式

¥For example, when an array is the result of a match between a regular expression and a string, the array returns properties and elements that provide information about the match. An array is the return value of RegExp.prototype.exec(), String.prototype.match(), and String.prototype.split(). For information on using arrays with regular expressions, see Regular Expressions.

使用类似数组的对象

¥Working with array-like objects

某些 JavaScript 对象(例如 document.getElementsByTagName() 返回的 NodeList 或在函数体内可用的 arguments 对象)表面上看起来和行为都像数组,但并不共享它们的所有方法。arguments 对象提供了 length 属性,但没有实现像 forEach() 这样的数组方法。

¥Some JavaScript objects, such as the NodeList returned by document.getElementsByTagName() or the arguments object made available within the body of a function, look and behave like arrays on the surface but do not share all of their methods. The arguments object provides a length attribute but does not implement array methods like forEach().

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

¥Array methods cannot be called directly on array-like objects.

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

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

¥But you can call them indirectly using Function.prototype.call().

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

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

¥Array prototype methods can be used on strings as well, since they provide sequential access to their characters in a similar way to arrays:

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