Array

JavaScript的 Array 对象是用于构造数组的全局对象,数组是类似于列表的高阶对象。

描述

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

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

常见操作

创建数组

let fruits = ['Apple', 'Banana']

console.log(fruits.length)
// 2

通过索引访问数组元素

let first = fruits[0]
// Apple

let last = fruits[fruits.length - 1]
// Banana

遍历数组

fruits.forEach(function(item, index, array) {
  console.log(item, index)
})
// Apple 0
// Banana 1

添加元素到数组的末尾

let newLength = fruits.push('Orange')
// ["Apple", "Banana", "Orange"]

删除数组末尾的元素

let last = fruits.pop() // remove Orange (from the end)
// ["Apple", "Banana"]

删除数组头部元素

let first = fruits.shift() // remove Apple from the front
// ["Banana"]

添加元素到数组的头部

let newLength = fruits.unshift('Strawberry') // add to the front
// ["Strawberry", "Banana"]

找出某个元素在数组中的索引

fruits.push('Mango')
// ["Strawberry", "Banana", "Mango"]

let pos = fruits.indexOf('Banana')
// 1

通过索引删除某个元素

let removedItem = fruits.splice(pos, 1) // this is how to remove an item

// ["Strawberry", "Mango"]

从一个索引位置删除多个元素

let vegetables = ['Cabbage', 'Turnip', 'Radish', 'Carrot']
console.log(vegetables)
// ["Cabbage", "Turnip", "Radish", "Carrot"]

let pos = 1
let n = 2

let removedItems = vegetables.splice(pos, n)
// this is how to remove items, n defines the number of items to be removed,
// starting at the index position specified by pos and progressing toward the end of array.

console.log(vegetables)
// ["Cabbage", "Carrot"] (the original array is changed)

console.log(removedItems)
// ["Turnip", "Radish"]

复制一个数组

let shallowCopy = fruits.slice() // this is how to make a copy
// ["Strawberry", "Mango"]

访问数组元素

JavaScript 数组的索引是从0开始的,第一个元素的索引为0,最后一个元素的索引等于该数组的 长度 减1。

如果指定的索引是一个无效值,JavaScript 数组并不会报错,而是会返回 undefined

let arr = ['this is the first element', 'this is the second element', 'this is the last element']
console.log(arr[0])              // logs 'this is the first element'
console.log(arr[1])              // logs 'this is the second element'
console.log(arr[arr.length - 1]) // logs 'this is the last element'

虽然数组元素可以看做是数组对象的属性,就像 toString 一样,但是下面的写法是错误的,运行时会抛出 SyntaxError 异常,而原因则是使用了非法的属性名:

console.log(arr.0) // a syntax error

并不是 JavaScript 数组有什么特殊之处,而是因为在 JavaScript 中,以数字开头的属性不能用点号引用,必须用方括号。

比如,如果一个对象有一个名为 3d 的属性,那么只能用方括号来引用它。下面是具体的例子:

let years = [1950, 1960, 1970, 1980, 1990, 2000, 2010]
console.log(years.0)   // a syntax error
console.log(years[0])  // works properly
renderer.3d.setTexture(model, 'character.png')     // a syntax error
renderer['3d'].setTexture(model, 'character.png')  // works properly

注意在 3d 那个例子中,引号是必须的。你也可以将数组的索引用引号引起来,比如 years[2] 可以写成 years['2']

years[2] 中的 2 会被 JavaScript 解释器通过调用 toString 隐式转换成字符串。正因为这样,'2''02'years 中所引用的可能是不同位置上的元素。而下面这个例子也可能会打印 true

console.log(years['2'] != years['02'])

数组长度与数字下标之间的关系

JavaScript 数组的 length 属性和其数字下标之间有着紧密的联系。

数组内置的几个方法(例如 joinsliceindexOf 等)都会考虑 length 的值。

另外还有一些方法(例如 pushsplice 等)还会改变 length 的值。

const fruits = []
fruits.push('banana', 'apple', 'peach')

console.log(fruits.length) // 3

使用一个合法的下标为数组元素赋值,并且该下标超出了当前数组的大小的时候,解释器会同时修改 length 的值:

fruits[5] = 'mango'
console.log(fruits[5])            // 'mango'
console.log(Object.keys(fruits))  // ['0', '1', '2', '5']
console.log(fruits.length)        // 6

也可以显式地给 length 赋一个更大的值:

fruits.length = 10
console.log(fruits)              // ['banana', 'apple', 'peach', empty x 2, 'mango', empty x 4]
console.log(Object.keys(fruits)) // ['0', '1', '2', '5']
console.log(fruits.length)       // 10
console.log(fruits[8])           // undefined

而为 length 赋一个更小的值则会删掉一部分元素:

fruits.length = 2
console.log(Object.keys(fruits)) // ['0', '1']
console.log(fruits.length)       // 2

这一节的内容在 Array.length 中有更详细的介绍。

正则匹配结果所返回的数组

使用正则表达式匹配字符串可以得到一个数组。这个数组中包含本次匹配的相关信息和匹配结果。RegExp.execString.matchString.replace 都会返回这样的数组。

看下面的例子和例子下面的表格:

// Match one d followed by one or more b's followed by one d
// Remember matched b's and the following d
// Ignore case

const myRe = /d(b+)(d)/i
const myArray = myRe.exec('cdbBdbsbz')

该正则匹配返回的数组包含以下属性和元素:

属性/元素 说明 示例
input
只读
正则表达式所匹配的原始字符串 "cdbBdbsbz"
index
只读
匹配到的子串在原始字符串中的索引 1
[0]
只读
最后匹配到的子串 "dbBd"
[1], ...[n]
只读
正则表达式中所指定的分组所匹配到的子串,其数量由正则中的分组数量决定,无最大上限 [1]: "bB"
[2]: "d"

构造器

Array()

创建一个新的 Array 对象

静态属性

get Array[@@species]

返回 Array 的构造函数

静态方法

Array.from()

从类数组对象或者可迭代对象中创建一个新的数组实例

Array.isArray()

用来判断某个变量是否是一个数组对象

Array.of()

根据一组参数来创建新的数组实例,支持任意的参数数量和类型

实例属性

Array.prototype.length

数组中的元素个数

Array.prototype[@@unscopables]

包含了所有 ES2015 (ES6) 中新定义的、且并未被更早的 ECMAScript 标准收纳的属性名。这些属性被排除在由 with 语句绑定的环境中

实例方法

Array.prototype.at() (en-US)

Returns the array item at the given index. Accepts negative integers, which count back from the last item.

Array.prototype.concat()

用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组

Array.prototype.copyWithin()

浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度

Array.prototype.entries()

返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键/值对

Array.prototype.every()

测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值

Array.prototype.fill()

用一个固定值填充一个数组中从起始索引到终止索引内的全部元素

Array.prototype.filter()

创建一个新数组, 其包含通过所提供函数实现的测试的所有元素

Array.prototype.find()

返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined

Array.prototype.findIndex()

返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回 -1

Array.prototype.flat()

按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回

Array.prototype.flatMap()

使用映射函数映射每个元素,然后将结果压缩成一个新数组

Array.prototype.forEach()

对数组的每个元素执行一次给定的函数

Array.prototype.includes()

判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回 false

Array.prototype.indexOf()

返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回 -1

Array.prototype.join()

将一个数组的所有元素连接成一个字符串并返回这个字符串

Array.prototype.keys()

返回一个包含数组中每个索引键的 Array Iterator 对象

Array.prototype.lastIndexOf()

返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1

Array.prototype.map()

返回一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值

Array.prototype.pop()

从数组中删除最后一个元素,并返回该元素的值

Array.prototype.push()

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

Array.prototype.reduce()

对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值

Array.prototype.reduceRight()

接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值

Array.prototype.reverse()

将数组中元素的位置颠倒,并返回该数组。该方法会改变原数组

Array.prototype.shift()

从数组中删除第一个元素,并返回该元素的值

Array.prototype.slice()

提取源数组的一部分并返回一个新数组

Array.prototype.some()

测试数组中是不是至少有一个元素通过了被提供的函数测试

Array.prototype.sort()

对数组元素进行原地排序并返回此数组

Array.prototype.splice()

通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容

Array.prototype.toLocaleString()

返回一个字符串表示数组中的元素。数组中的元素将使用各自的 Object.prototype.toLocaleString() 方法转成字符串

Array.prototype.toString()

返回一个字符串表示指定的数组及其元素。数组中的元素将使用各自的 Object.prototype.toString() 方法转成字符串

Array.prototype.unshift()

将一个或多个元素添加到数组的头部,并返回该数组的新长度

Array.prototype.values()

返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值

Array.prototype[@@iterator]()

返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值

示例

创建数组

下面这个例子创建了一个长度为 0 的数组 msgArray,然后给 msgArray[0] 和 msgArray[99] 赋值,从而导致数组长度变为了 100

let msgArray = []
msgArray[0] = 'Hello'
msgArray[99] = 'world'

if (msgArray.length === 100) {
  console.log('The length is 100.')
}

创建二维数组

下面的例子创建了一个代表国际象棋棋盘的二维数组,然后将 [6][4] 上的 p (Pawn 兵) 拷贝到 [4][4],而原本的 [6][4] 位置则被设置为空格。

let board = [
  ['R','N','B','Q','K','B','N','R'],
  ['P','P','P','P','P','P','P','P'],
  [' ',' ',' ',' ',' ',' ',' ',' '],
  [' ',' ',' ',' ',' ',' ',' ',' '],
  [' ',' ',' ',' ',' ',' ',' ',' '],
  [' ',' ',' ',' ',' ',' ',' ',' '],
  ['p','p','p','p','p','p','p','p'],
  ['r','n','b','q','k','b','n','r'] ]

console.log(board.join('\n') + '\n\n')

// Move King's Pawn forward 2
board[4][4] = board[6][4]
board[6][4] = ' '
console.log(board.join('\n'))

下面是输出:

R,N,B,Q,K,B,N,R
P,P,P,P,P,P,P,P
 , , , , , , ,
 , , , , , , ,
 , , , , , , ,
 , , , , , , ,
p,p,p,p,p,p,p,p
r,n,b,q,k,b,n,r

R,N,B,Q,K,B,N,R
P,P,P,P,P,P,P,P
 , , , , , , ,
 , , , , , , ,
 , , , ,p, , ,
 , , , , , , ,
p,p,p,p, ,p,p,p
r,n,b,q,k,b,n,r

用数组将一组值以表格形式显示

values = []
for (let x = 0; x < 10; x++){
 values.push([
  2 ** x,
  2 * x ** 2
 ])
}
console.table(values)

结果为:

// The first column is the index
0	1	0
1	2	2
2	4	8
3	8	18
4	16	32
5	32	50
6	64	72
7	128	98
8	256	128
9	512	162

规范

Specification
ECMAScript Language Specification (ECMAScript)
# sec-array-objects

浏览器兼容性

BCD tables only load in the browser

相关链接