Array
Array
Array 概述
数组是一种类列表对象,是值的有序集合,它的键名是按次序排列的一组整数(0,1,2...)。
JavaScript 数组使用一个 32 位整数保存数组的元素个数。数组的索引从
0
开始,数组最大能容纳4294967295
(即2^32-1
)个元素。数组元素是对象属性,JavaScript 语法要求使用方括号表示法(或用引号包裹数组下标)访问以数字开头的属性。
const arr = ['a', 'b', 'c', 'd', 'e', 'f'] // JavaScript 引擎通过隐式的 toString,将 arr[1] 中的 1 强制转换为字符串。 arr[1] // b arr[1.00] // b arr['1'] // b // '1' 和 '01' 将指向 arr 对象上的两个不同的槽位 arr['01'] // undefined
// 使用 Object.keys 方法返回数组的所有键名 const arr = ['a', 'b', 'c', 'd', 'e', 'f'] Object.keys(arr) // ['0', '1', '2', '3', '4', '5']
每个 JavaScript 数组都有一个
length
属性,该属性是一个动态值。针对非稀疏数组,length
属性就是数组元素的个数;针对稀疏数组,length
比所有元素的索引都要大。let arr = ['a', 'b', 'c'] // arr.length 为 3 console.log(arr.length) // 3 // 设置数组的 length 属性【小于】当前数组成员个数的值 // 该数组的成员数量会自动【减少】到 length 设置的值 arr.length = 2 console.log(arr) // ['a', 'b'] // 设置数组的 length 属性【大于】当前数组成员个数的值 // 该数组的成员数量会自动【增加】到 length 设置的值,新增的位置都是空位 // 读取新增的位置会返回 undefined arr.length = 4 console.log(arr) // ['a', 'b', empty × 2] console.log(arr[3]) // undefined // 清空数组的一个有效方法,就是设置数组的 length 属性为 0 arr.length = 0 console.log(arr) // [] // 设置数组的 length 属性为不合法的值,JavaScript 会报错 [].length = -1 // Uncaught RangeError: Invalid array length [].length = Math.pow(2, 32) // Uncaught RangeError: Invalid array length [].length = 'abc' // Uncaught RangeError: Invalid array length // 数组本质上是一种对象,可以为数组添加属性,但是这影响 length 属性的值 // length 属性的值等于最大的数字键加 1,数组如果没有整数键,所以 length 属性保持为 0 let arr = [] arr['abc'] = 'abc' console.log(arr.length) // 0 arr[2.1] = 'abc' console.log(arr.length) // 0 console.log(arr) // [abc: 'abc', 2.1: 'abc'] // 数组的键名添加超过范围的数值,该键名会自动转为字符串 let arr = [] arr[-1] = 'a' arr[Math.pow(2, 32)] = 'b' console.log(arr.length) // 0 console.log(arr) // [-1: 'a', 4294967296: 'b'] console.log(arr[-1]) // 'a' console.log(arr[4294967296]) // 'b'
JavaScript 数组是动态的,并且可以包含不同的数据类型。
- 在创建数组时无需声明一个固定的大小或者在数组大小变化时无需重新分配空间。
- 数组中包含数组称之为多维数组。可以通过将两组方括号链接在一起来访问数组内的另一个数组。
JavaScript 数组不是关联数组(具有命名索引的数组,可以使用字符串或者其他类型的值作为索引),不能使用任意字符串作为索引访问数组元素,必须使用非负整数(或者非负整数的字符串形式)作为索引访问。
JavaScript 数组可能是稀疏数组,数组元素的索引不一定要连续的,它们之间可以有空缺。
稀疏数组的特性
- 含有空元素
empty
的数组。索引不连续,数组长度大于元素个数的数组。数组的空位是可读取的,返回undefined
。 - 在大多数遍历数组的方法中,遇到
empty
元素的时候,callback
函数是不会执行的。比如forEach
、for...in
以及Object.keys
方法进行遍历,空位都会被跳过。如果某个位置是undefined
,遍历的时候则不会被跳过。 - 稀疏数组在访问元素的速度上比密集数组慢。
- 稀疏数组在一些数组方法中与密集数组存在差异。
- 含有空元素
生成稀疏数组
let sparseArr01 = new Array(5) console.log('sparseArr01 : ', sparseArr01) // sparseArr02 : [empty × 5] let sparseArr02 = [] sparseArr02[4] = 4 console.log('sparseArr02 : ', sparseArr02) // sparseArr02 : [empty × 4, 5] let sparseArr03 = [] sparseArr03.length = 5 console.log('sparseArr03 : ', sparseArr03) // sparseArr03 : [empty × 5] let sparseArr04 = [0, , , , ,] console.log('sparseArr04 : ', sparseArr04) // sparseArr04 : [0, empty × 4] let sparseArr05 = [0, 1, 2, 3, 4] delete sparseArr05[4] console.log('sparseArr05 : ', sparseArr05) // sparseArr05 : [0, 1, 2, 3, empty]
empty
VSundefined
let sparseArr = new Array(3) console.log(sparseArr) // [empty × 3] console.log(sparseArr[0]) // undefined let undefinedArr = [undefined, undefined, undefined] console.log(undefinedArr) // [undefined, undefined, undefined] console.log(undefinedArr[0]) // undefined sparseArr.forEach(item => console.log(item)) // 无 console.log 输出 undefinedArr.forEach(item => console.log(item)) // 输出如下: // undefined // undefined // undefined // 使用 in 运算符判断指定属性是否在指定对象或原型链中 // sparseArr 的键名都是空的 // undefinedArr 的键名是有值的 0 in sparseArr // false 0 in undefinedArr // true
稀疏数组转密集数组
let sparseArr = [0, , , , ,] console.log('sparseArr : ', sparseArr) // sparseArr : [0, empty × 4] Array.apply(null, sparseArr) // [0, undefined, undefined, undefined, undefined] Array.from(sparseArr) // [0, undefined, undefined, undefined, undefined] [...sparseArr] // // [0, undefined, undefined, undefined, undefined]
创建数组
数组直接量(字面量)
let emptyArr = [] // 没有元素的数组 let number = 1 let numberArr = [number, number + 1, number + 2]
Array()
构造函数:用于创建Array
对象。// 无参数时,返回一个空数组 new Array() // [] // 单个正整数参数,表示返回的新数组的长度 new Array(1) // [empty] new Array(2) // [empty × 2] // 单个非数值(比如字符串、布尔值、对象等)作为参数, // 则该参数是返回的新数组的成员 new Array('abc') // ['abc'] new Array([1]) // [Array(1)] // 多参数时,所有参数都是返回的新数组的成员 new Array(1, 2) // [1, 2] new Array('a', 'b', 'c') // ['a', 'b', 'c'] // 非正整数的数值作为参数,会报错 new Array(3.2) // Uncaught RangeError: Invalid array length new Array(-3) // Uncaught RangeError: Invalid array length
Array.of()
语法:
Array.of(element0, element1, /* … ,*/ elementN)
描述: 通过参数值以及参数顺序创建一个新的 Array 实例,而不考虑参数的数量或类型。
Array.of() // [] Array.of(undefined) // [undefined] Array.of(1) // [1] Array.of(1, 2) // [1, 2] Array.of(1, { a: 1 }, null, undefined) // [1, { a: 1 }, null, undefined] // 模拟 Array.of() function ArrayOf() { return [].slice.call(arguments) }
Array.from()
语法:
Array.from(arrayLike, mapFn, thisArg)
描述: 通过类数组对象或者可迭代对象(包括
Set
和Map
数据结构)创建一个新的浅拷贝的数组实例。参数:
arrayLike
:需要转换成数组的类数组对象或可迭代对象。- 类数组对象:带有
length
属性和索引元素的对象。比如:document.getElementsByTagName()
返回的NodeList
、arguments
等对象。 - 可迭代对象:如
String
、Set
、Map
- 类数组对象:带有
mapFn
:可选值。arrayLike
中的值都会执行mapFn
回调函数,函数返回值将添加到数组中。该函数接收以下参数:element
:数组当前正在处理的元素index
:数组当前正在处理元素的索引
thisArg
:可选值。执行mapFn
时用作this
的值。
// 如果参数是真正的数组,Array.from() 会返回相同的数组 Array.from([1, 2, 3]) // [1, 2, 3] Array.from([1, , 3], element => element || 0) // [1, 0, 3]
// 类数组对象:其本质特征必须有 length 属性 // 比如: document.getElementsByTagName() 返回的 NodeList 、 arguments 等对象 let arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3, } // ES5 的写法 let arr1 = [].slice.call(arrayLike) // ['a', 'b', 'c'] Array.from(arrayLike) // ['a', 'b', 'c'] ,ES6 的写法 Array.from(arrayLike, (element, index) => element + index) // ['a0', 'b1', 'c2'] // 等同于 Array.from(arrayLike).map((element, index) => element + index) Array.from({ length: 3 }) // [undefined, undefined, undefined] Array.from({ length: 3 }, (element, index) => index) // [0, 1, 2] // 根据 DOM 元素的属性创建一个数组 const images = document.querySelectorAll('img') const sources = Array.from(images, (image) => image.src)
// 部署了 Iterator 接口的数据结构,Array.from() 都能将其转为数组。 // 比如:String、Set、Map Array.from('hello') // ['h', 'e', 'l', 'l', 'o'] Array.from(new Set(['a', 'b'])) // ['a', 'b'] let map01 = new Map([ ['1', 'a'], ['2', 'b'], ]) Array.from(map01) // [['1', 'a'], ['2', 'b']] Array.from(map01.values()) // ['a', 'b'] Array.from(map01.keys()) // ['1', '2']
Array.from()
方法的应用:进行数组合并去重
function combine() { let arr = [].concat.apply([], arguments) // 没有去重复的新数组,之后用 Set 数据结构的特性来去重 return Array.from(new Set(arr)) } const arr01 = [1, 2, 2] const arr02 = [2, 3, 3] console.log(combine(arr01, arr02)) // [1, 2, 3]
将字符串转换为数组,返回字符串长度,避免 JavaScript 将大于
\uFFFF
的 Unicode 字符算作两个字符的问题。function countSymbols(string) { return Array.from(string).length }
Array.fromAsync()
语法:
Array.fromAsync(arrayLike, mapFn, thisArg)
描述: 通过异步可迭代对象、可迭代对象或类数组对象创建一个新的浅拷贝的
Array
实例。参数:
arrayLike
:需要转换为数组的异步可迭代、可迭代或类数组对象。- 异步可迭代对象:
ReadableStream
和AsyncGenerator
- 可迭代对象:
String
、Set
、Map
- 类数组对象:带有
length
属性和索引元素的对象。比如:document.getElementsByTagName()
返回的NodeList
、arguments
等对象。
- 异步可迭代对象:
mapFn
:可选值。arrayLike
中的值都会执行mapFn
回调函数,函数返回值将添加到数组中(在等待兑现后)。该函数接收以下参数:element
:数组当前正在处理的元素。由于所有元素都会先等待其兑现,因此该值永远不会是thenable
。index
:数组当前正在处理元素的索引
thisArg
:可选值。执行mapFn
时用作this
的值。
Array.fromAsync()
在行为上与Array.from()
几乎等价,主要区别如下:Array.fromAsync()
可以处理异步可迭代对象。Array.fromAsync()
返回一个会兑现为数组实例的Promise
。- 如果使用非异步可迭代对象调用
Array.fromAsync()
,则要添加到数组中的每个元素(无论是否为Promise
)都会先等待其兑现。 - 如果提供了
mapFn
,则其输入和输出会在内部等待兑现。
Array.fromAsync()
和Promise.all()
都可以将一个Promise
可迭代对象转换为一个数组的Promise
。主要区别如下:Array.fromAsync()
会依次等待对象中产生的每个值兑现。Promise.all()
会并行等待所有值兑现。Array.fromAsync()
惰性迭代可迭代对象,并且不会获取下一个值,直到当前值被兑现。Promise.all()
预先获取所有值并等待它们全部兑现。
const asyncIterable = (async function* () { for (let i = 0; i < 5; i++) { await new Promise((resolve) => setTimeout(resolve, 10 * i)) yield i } })() Array.fromAsync(asyncIterable).then((array) => console.log(array)) // [0, 1, 2, 3, 4] Array.fromAsync( new Map([ [1, 2], [3, 4], ]) ).then((array) => console.log(array)) // [[1, 2], [3, 4]] Array.fromAsync( new Set([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]) ).then((array) => console.log(array)) // [1, 2, 3] Array.fromAsync({ length: 3, 0: Promise.resolve(1), 1: Promise.resolve(2), 2: Promise.resolve(3), }).then((array) => console.log(array)) // [1, 2, 3]
检测数组
Array.isArray()
语法:
Array.isArray(value)
描述: 用于确认
value
是否是一个Array
。参数:
- 如果
value
是Array
实例,则返回为true
,否则为false
。 - 如果
value
是TypeArray
实例(如:Int8Array
、Uint8Array
等),则返回为false
。
// 以下的函数调用都返回 true Array.isArray([]) Array.isArray([1]) Array.isArray(new Array()) Array.isArray(new Array('a', 'b', 'c', 'd')) Array.isArray(new Array(3)) Array.isArray(Array.prototype) // Array.prototype 也是一个数组 // 以下的函数调用都返回 false Array.isArray() Array.isArray({}) Array.isArray(null) Array.isArray(undefined) Array.isArray(17) Array.isArray('Array') Array.isArray(true) Array.isArray(false) Array.isArray(new Uint8Array(32)) // 这不是一个数组,因为不是使用数组字面量语法或 Array 构造函数创建的 Array.isArray({ __proto__: Array.prototype })
instanceof
VSArray.isArray()
Array.isArray()
优于instanceof
,因为Array.isArray()
能跨领域工作。- 如果网页里有多个框架,则可能涉及两个不同的全局执行上下文,可能存在有两个不同版本的
Array
构造函数。如果要把数组从一个框架传给另一个框架,则这个数组的构造函数将有别于在第二个框架内本地创建的数组。使用Array.isArray()
可以不用区分Array
是在哪个全局执行上下文中创建的。
const iframe = document.createElement('iframe') document.body.appendChild(iframe) const xArray = window.frames[window.frames.length - 1].Array const arr = new xArray(1, 2, 3) // [1, 2, 3] // 正确检查 Array Array.isArray(arr) // true // arr 的原型是 xArray.prototype,不同于 Array.prototype 的对象 arr instanceof Array // false
- 如果
迭代器方法
Array.prototype.keys()
语法:
arr.keys()
描述: 返回一个新的数组迭代器对象,其中包含数组中每个索引的键。
- 当读取稀疏数组的键时,
keys()
方法不会忽略缺失属性的键。 - 当读取类数组对象的键时,
keys()
方法会读取this
的length
属性,生成0
到length - 1
之间的所有整数索引。实际并不会访问索引。
let arr = ['a', 'b', 'c'] console.log([...arr.keys()]) // [0, 1, 2] let sparseArr = ['a', , 'c'] let iterator = sparseArr.keys() console.log(iterator.next()) // { value: 0, done: false } console.log(iterator.next()) // { value: 1, done: false } console.log(iterator.next()) // { value: 2, done: false } console.log(iterator.next()) // { value: undefined, done: true } console.log([...sparseArr.keys()]) // [0, 1, 2] console.log(Object.keys(sparseArr)) // ['0', '2'] const arrayLike = { length: 3, } console.log([...Array.prototype.keys.call(arrayLike)]) // [0, 1, 2]
- 当读取稀疏数组的键时,
Array.prototype.values()
语法:
arr.values()
描述: 返回一个新的数组迭代器对象,该对象迭代数组中每个元素的值。
- 当读取稀疏数组的键时,
values()
方法会将空槽作为undefined
迭代。 - 当读取类数组对象的键时,
values()
方法会读取this
的length
属性,然后访问每个整数索引。
let arr = ['a', 'b', 'c'] console.log([...arr.values()]) // ['a', 'b', 'c'] let sparseArr = ['a', , 'c'] let iterator = sparseArr.values() console.log(iterator.next()) // { value: 'a', done: false } console.log(iterator.next()) // { value: undefined, done: false } console.log(iterator.next()) // { value: 'c', done: false } console.log(iterator.next()) // { value: undefined, done: true } console.log([...sparseArr.values()]) // ['a', undefined, 'c'] console.log(Object.values(sparseArr)) // ['a', 'c'] const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3, } console.log([...Array.prototype.values.call(arrayLike)]) // ['a', 'b', 'c']
- 当读取稀疏数组的键时,
Array.prototype.entries()
语法:
arr.entries()
描述: 返回一个新的数组迭代器对象,该对象包含数组中每个索引的键/值对。
- 当读取稀疏数组的键时,
entries()
方法不会忽略缺失属性的键,会将空槽的值作为undefined
。 - 当读取类数组对象的键时,
entries()
方法会读取this
的length
属性,然后访问每个整数索引。
let arr = ['a', 'b', 'c'] console.log([...arr.entries()]) // [[0, 'a'], [1, 'b'], [2, 'c']] let sparseArr = ['a', , 'c'] let iterator = sparseArr.entries() console.log(iterator.next()) // { value: [0, 'a'], done: false } console.log(iterator.next()) // { value: [1, undefined], done: false } console.log(iterator.next()) // { value: [2, 'c'], done: false } console.log(iterator.next()) // { value: undefined, done: true } console.log([...sparseArr.entries()]) // [[0, 'a'], [1, undefined], [2, 'c']] console.log(Object.entries(sparseArr)) // [['0', 'a'], ['2', 'c']] const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3, } console.log([...Array.prototype.entries.call(arrayLike)]) // [[0, 'a'], [1, 'b'], [2, 'c']]
- 当读取稀疏数组的键时,
复制和填充方法
Array.prototype.copyWithin()
语法:
arr.copyWithin(target, start, end)
描述: 浅拷贝数组的一部分到同一数组中的另一个位置,并返回它。
- 不会改变原数组的长度,会改变原数组。
- 如果复制的区域是稀疏的(含有空元素
empty
),原来的empty
元素会被删除并替换为拷贝的empty
元素。 - 当读取类数组对象的键时,
copyWithin()
方法会读取this
的length
属性,然后操作所涉及的整数索引。
参数:
target
:序列开始替换的目标位置,以0
为起始的下标,且将被转换为整数。- 如果
target < 0
,则从数组末尾开始计数(即:target + arr.length
)。 - 如果
target < -arr.length
,则使用0
。 - 如果
target >= array.length
,则不会拷贝任何内容。 - 如果
target
位于start
之后,则复制只会持续到array.length
结束(即:copyWithin()
永远不会扩展数组)。
- 如果
start
:可选值。要复制的元素序列的起始位置,以0
为起始的下标表示,且将被转换为整数。- 如果
start < 0
,将从数组末尾开始计数(即:start + arr.length
)。 - 如果
start < -arr.length
或start
省略,则默认为0
。 - 如果
start >= arr.length
,则不会拷贝任何内容。
- 如果
end
:可选值。要复制的元素序列的结束位置(不包含该位置),以0
为起始的下标表示,且将被转换为整数。- 如果
end < 0
,将从数组末尾开始计数(即:end + arr.length
)。 - 如果
end < -arr.length
,则使用0
。 - 如果
end >= arr.length
或end
省略,则默认为arr.length
,会导致直到数组末尾的所有元素都被复制。 - 如果
end
位于start
之前,则不会拷贝任何内容。
- 如果
// 将数组中从下标 0 到数组结束的元素(包含)复制到从下标 3 开始的位置 [1, 2, 3, 4, 5].copyWithin(-2) // [1, 2, 3, 1, 2] // 将数组中从下标 3 到数组结束的元素(包含)复制到从下标 0 开始的位置 [1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5] // 将数组中从下标 3 到下标 4 (不包含) 的元素复制到从下标 0 开始的位置 [1, 2, 3, 4, 5].copyWithin(0, 3, 4) // [4, 2, 3, 4, 5] // 将数组中从下标 2 到下标 4 (不包含)的元素复制到从下标 3 开始的位置 [1, 2, 3, 4, 5].copyWithin(-2, -3, -1) // [1, 2, 3, 3, 4] // 将数组中从下标 1 到下标 2 (不包含)的元素复制到从下标 2 开始的位置 [1, , 3].copyWithin(2, 1, 2) // [1, empty × 2] [].copyWithin.call({ length: 5, 3: 1 }, 0, 3) // { 0: 1, 3: 1, length: 5 }
Array.prototype.fill()
语法:
arr.fill(value, start, end)
描述: 用一个固定值
value
填充一个数组中从起始索引start
(默认为0
)到终止索引end
(默认为arr.length
,不包含)内的全部元素,并返回修改后的数组。- 不会改变原数组的长度,会改变原数组。
- 对于稀疏数组,会使用
value
填充稀疏数组的空槽(empty
元素)。 - 对于类数组对象,读取
this
的length
属性,并设置从start
到end
的每个整数属性的值。
参数:
value
:用来填充数组元素的值。如果value
是个对象,数组中每一项都会引用这个元素。start
:基于零的索引,从此开始填充。会被转为整数。- 如果
start < 0
,则从数组末尾开始计数(即:start + arr.length
)。 - 如果
start < -arr.length
或start
被省略,则默认为0
。 - 如果
start >= arr.length
,则没有索引被填充。
- 如果
end
:基于零的索引,在此结束填充,但不包含end
索引。会被转为整数。- 如果
end < 0
,则从数组末尾开始计数(即:end + arr.length
)。 - 如果
end < -arr.length
或end
被省略,则默认为0
。 - 如果
end >= arr.length
,则使用arr.length
,导致所有索引被填充。 - 如果
end
的位置在start
之前,则没有索引被填充。
- 如果
[1, 2, 3].fill(4) // [4, 4, 4] [1, 2, 3].fill(4, 1) // [1, 4, 4] [1, 2, 3].fill(4, 1, 2) // [1, 4, 3] [1, 2, 3].fill(4, 1, 1) // [1, 2, 3] [1, 2, 3].fill(4, 3, 3) // [1, 2, 3] [1, 2, 3].fill(4, -3, -2) // [1, 2, 3] [1, 2, 3].fill(4, NaN, NaN) // [1, 2, 3] [1, 2, 3].fill(4, NaN, NaN) // [1, 2, 3] [1, 2, 3].fill(4, 3, 5) // [1, 2, 3] Array(3).fill(4) // [4, 4, 4] let fillFooArr = Array(3).fill({ foo: 'foo' }) // [{ foo: 'foo' }, { foo: 'foo' }, { foo: 'foo' }] fillFooArr[0].foo = 'bar' // [{ foo: 'bar' }, { foo: 'bar' }, { foo: 'bar' }] let arrayLike = { length: 2 } Array.prototype.fill.call(arrayLike, 1) // { 0: 1, 1: 1, length: 2 }
转换方法
Array.prototype.join()
语法:
arr.join(separator)
描述: 将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回,用逗号或指定的分隔符字符串分隔。
- 如果
arr.length
为0
,则返回空字符串(''
)。 - 如果
arr.length
为1
,则返回该元素而不使用分隔符。 - 如果一个元素是
undefined
或null
,会被转换为空字符串(''
),而不是字符串'undefined'
或'null'
。 - 对于稀疏数组,迭代时会把空槽(
empty
元素)当作undefined
处理。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
参数:
separator
:可选值。指定一个字符串来分隔数组的每个元素。- 如果省略,数组元素用逗号(
,
)分隔。 - 如果是空字符串(
''
),则所有元素之间都没有任何字符。
- 如果省略,数组元素用逗号(
- 如果
Array.prototype.toLocaleString()
语法:
arr.toLocaleString(locales, options)
描述: 返回一个字符串,表示数组中的所有元素。每个元素通过调用自己的
toLocaleString()
方法转换为字符串,并且使用分隔符(例如逗号,
,取决于当前的语言环境)将转换后的字符串拼接起来。- 相关元素调用的
toLocaleString()
方法:Object
:Object.prototype.toLocaleString()
Number
:Number.prototype.toLocaleString()
Date
:Date.prototype.toLocaleString()
- 如果元素是
undefined
或null
,会被转化为空字符串''
。 - 对于稀疏数组,迭代时会把空槽(
empty
元素)当作undefined
处理。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
const arr = [1, 'foo', undefined, null, , { a: 1 }] arr.join() // '1,foo,,,,[object Object]' arr.join('') // '1foo[object Object]' arr.join('+') // '1+foo++++[object Object]' // 稀疏数组 [1,,3].join() // '1,,3' // 类数组对象 const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3, } Array.prototype.join.call(arrayLike) // 'a,b,c'
参数:
locales
:可选值。带有 BCP 47 语言标签的字符串,或者此类字符串的数组。options
:可选值。一个具有配置属性的对象。
let arr = [ 1, 'foo', undefined, null, , { a: 1 }, new Set(), new Map(), new Date(), ] arr.toLocaleString() // '1,foo,,,,[object Object],[object Set],[object Map],2023/8/13 23:42:27' // 稀疏数组 [1, , 3].toLocaleString() // '1,,3' // 类数组对象 const arrayLike = { 0: 1, 1: 2, 2: 3, length: 3, } Array.prototype.toLocaleString.call(arrayLike) // '1,2,3'
- 相关元素调用的
Array.prototype.toString()
语法:
arr.toString()
描述: 返回一个字符串,表示指定的数组及其元素。
- 数组的
toString()
方法实际上在内部调用了join()
方法来拼接数组并返回一个包含所有数组元素的字符串,元素之间用逗号(','
)分隔。 - 如果
join()
方法不可用或者不是函数,则会使用Object.prototype.toString
来代替,并返回[object Array]
。 - 如果元素是
undefined
或null
,会被转化为空字符串''
。 - 对于稀疏数组,迭代时会把空槽(
empty
元素)当作undefined
并生成一个额外的分隔符。 - 对于类数组对象,期望
this
具有join()
方法;如果不存在,则使用Object.prototype.toString()
。
let arr = [ 1, 'foo', undefined, null, , { a: 1 }, new Set(), new Map(), new Date(), ] arr.toString() // '1,foo,,,,[object Object],[object Set],[object Map],2023/8/13 23:50:47' // 稀疏数组 [1, , 3].toString() // '1,,3' // 类数组对象 Array.prototype.toString.call({ join: () => 1 }) // 1 Array.prototype.toString.call({ join: () => undefined }) // undefined Array.prototype.toString.call({ join: 'not function' }) // '[object Object]'
- 数组的
搜索与位置查找方法
Array.prototype.includes()
语法:
arr.includes(searchElement, fromIndex)
描述: 判断一个数组是否包含一个指定的值。如果包含(或者如果指定了
fromIndex
,找到searchElement
值)则返回true
,否则返回false
。该方法使用
零值相等
算法将searchElement
与数组中的元素进行比较。0
、-0
、+0
都被认为是相等的。false
不被认为与0
相等。NaN
可以被正确的搜索到。
零值相等与严格相等的区别在于其将
NaN
视作是相等的,与同值相等的区别在于其将-0
和0
视作相等的。// 零值相等不作为 JavaScript API 公开,但可以通过自定义代码实现 function sameValueZero(x, y) { if (typeof x === 'number' && typeof y === 'number') { // x 和 y 相等(可能是 -0 和 0)或它们都是 NaN return x === y || (x !== x && y !== y) } return x === y }
对于稀疏数组,迭代时会把空槽(
empty
元素)当作undefined
处理。对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
参数:
searchElement
:需要查找的值。fromIndex
:可选值。开始搜索的索引(从零开始)。- 如果
fromIndex < 0
,则从数组末尾开始计数(即fromIndex + array.length
)。 - 如果
fromIndex < -array.length
或者省略fromIndex
,则使用0
,会导致整个数组被搜索。 - 如果
fromIndex >= array.length
,则不会搜索数组并返回false
。
- 如果
[1, 2, 3].includes(2) // true ['1', '2', '3'].includes(3) // false [1, 2, 3].includes(3, 3) // false [1, 2, 3].includes(3, -1) // true [1, 2, 3].includes(3, -100) // true [1, 2, NaN].includes(NaN) // true [0, 2, 3].includes(+0) // true // 稀疏数组 [1, , 3].includes(undefined) // true // 类数组对象 const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3, } Array.prototype.includes.call(arrayLike, 'b') // true
Array.prototype.indexOf()
语法:
arr.indexOf(searchElement, fromIndex)
描述: 返回数组中第一次出现给定元素的下标,如果不存在则返回
-1
。- 该方法使用
严格相等(===)
算法将searchElement
与数组中的元素进行比较。NaN
值永远不会被比较为相等。 - 对于稀疏数组,迭代时会把跳过空槽(
empty
元素)。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
参数:
searchElement
:需要查找的值。fromIndex
:可选值。开始搜索的索引(从零开始)。- 如果
fromIndex < 0
,则从数组末尾开始计数(即fromIndex + array.length
)。 - 如果
fromIndex < -array.length
或者省略fromIndex
,则使用0
,会导致整个数组被搜索。 - 如果
fromIndex >= array.length
,则不会搜索数组并返回-1
。
- 如果
let arr = [1, 2, 2, , NaN] arr.indexOf(1) // 0 arr.indexOf(1, -5) // 0 arr.indexOf(2) // 1 arr.indexOf(2, 2) // 2 arr.indexOf(3) // -1 arr.indexOf(NaN) // -1 // 稀疏数组 [1, , 3].indexOf(undefined) // -1 // 类数组对象 const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3, } Array.prototype.indexOf.call(arrayLike, 'b') // 1
- 该方法使用
Array.prototype.lastIndexOf()
语法:
arr.lastIndexOf(searchElement, fromIndex)
描述: 返回数组中最后一次出现给定元素的索引,如果不存在则返回
-1
。该方法从fromIndex
开始向前搜索数组。- 该方法使用
严格相等(===)
算法将searchElement
与数组中的元素进行比较。NaN
值永远不会被比较为相等。 - 对于稀疏数组,迭代时会把跳过空槽(
empty
元素)。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
参数:
searchElement
:需要查找的值。fromIndex
:可选值。反向搜索的起始位置(从零开始)。- 如果
fromIndex < 0
,则从数组末尾开始计数(即fromIndex + array.length
)。 - 如果
fromIndex < -array.length
,则不搜索数组并返回-1
。 - 如果
fromIndex >= array.length
或者省略fromIndex
,则使用array.length - 1
,会导致整个数组被搜索。
- 如果
let arr = [1, 2, 2, , NaN] arr.lastIndexOf(1) // 0 arr.lastIndexOf(1, -5) // 0 arr.lastIndexOf(2) // 2 arr.lastIndexOf(2, 2) // 2 arr.lastIndexOf(2, 1) // 1 arr.lastIndexOf(3) // -1 arr.lastIndexOf(NaN) // -1 // 稀疏数组 [1, , 3].lastIndexOf(undefined) // -1 // 类数组对象 const arrayLike = { 0: 'a', 1: 'b', 2: 'b', length: 3, } Array.prototype.lastIndexOf.call(arrayLike, 'b') // 2
- 该方法使用
Array.prototype.find()
语法:
arr.find(callbackFn, thisArg)
描述: 返回数组中满足提供的
callbackFn
函数的第一个元素的值,否则返回undefined
。- 不会改变原数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度会被保存。callbackFn
不会访问超出数组初始长度的任何元素。- 对已经访问过的索引的更改,不会导致再次在这些元素上调用
callbackFn
。 - 如果
callbackFn
更改了数组中现有的、尚未访问的元素,传递给callbackFn
的值将是该元素被访问时的值。被删除的元素被视为undefined
。
- 对于稀疏数组,未赋值的空槽(
empty
元素)当作undefined
处理。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
参数:
callbackFn
:数组中的每个元素执行的回调函数,该函数应该返回一个Truthy
(真值)来表示已经找到了匹配的元素。该函数接收以下参数:element
:数组中当前正在处理的元素。index
:正在处理的元素在数组中的索引。array
:调用了find()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。
const inventory = [ { name: 'apples', quantity: 2 }, { name: 'bananas', quantity: 0 }, ] inventory.find(({ name }) => name === 'bananas') // { name: 'bananas', quantity: 0 } // 稀疏数组 [0, 1, , , , 5].find((item) => item === undefined) // undefined // 类数组对象 const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3, } Array.prototype.find.call(arrayLike, (x) => !Number.isInteger(x)) // 'a'
- 不会改变原数组,提供
Array.prototype.findIndex()
语法:
arr.findIndex(callbackFn, thisArg)
描述: 返回数组中满足提供的
callbackFn
函数的第一个元素的索引。若没有找到对应元素则返回-1
。- 不会改变原数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度会被保存。callbackFn
不会访问超出数组初始长度的任何元素。- 对已经访问过的索引的更改,不会导致再次在这些元素上调用
callbackFn
。 - 如果
callbackFn
更改了数组中现有的、尚未访问的元素,传递给callbackFn
的值将是该元素被访问时的值。被删除的元素被视为undefined
。
- 对于稀疏数组,未赋值的空槽(
empty
元素)当作undefined
处理。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
参数:
callbackFn
:数组中的每个元素执行的回调函数,该函数应该返回一个Truthy
(真值)来表示已经找到了匹配的元素。该函数接收以下参数:element
:数组中当前正在处理的元素。index
:正在处理的元素在数组中的索引。array
:调用了findIndex()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。
const inventory = [ { name: 'apples', quantity: 2 }, { name: 'bananas', quantity: 0 }, ] inventory.findIndex(({ name }) => name === 'bananas') // 1 // 稀疏数组 [0, 1, , , , 5].findIndex((item) => item === undefined) // 2 // 类数组对象 const arrayLike = { 0: 0, 'foo': 'fooVal', 1: 7.3, 2: 2, length: 3, } Array.prototype.findIndex.call(arrayLike, (x) => !Number.isInteger(x)) // 1
- 不会改变原数组,提供
Array.prototype.findLast()
语法:
arr.findLast(callbackFn, thisArg)
描述: 反向迭代数组,并返回满足提供的
callbackFn
函数的第一个元素的值。如果没有找到对应元素,则返回undefined
。- 不会改变被调用的数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度会被保存。callbackFn
不会访问超出数组初始长度的任何元素。- 对于已经访问过的索引重新赋值不会再次调用
callbackFn
。 - 如果
callbackFn
更改了数组中现有的、尚未访问的元素,传递给callbackFn
的值将是该元素被访问时的值。被删除的元素被视为undefined
。
- 对于稀疏数组,未赋值的空槽(
empty
元素)当作undefined
处理。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
参数:
callbackFn
:数组中的每个元素执行的回调函数,该函数应该返回一个Truthy
(真值)来表示已经找到了匹配的元素。该函数接收以下参数:element
:数组中当前正在处理的元素。index
:正在处理的元素在数组中的索引。array
:调用了findLast()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。
const inventory = [ { name: 'apples', quantity: 2 }, { name: 'bananas', quantity: 0 }, { name: "cherries", quantity: 5 }, ] inventory.findLast(({ name }) => name === 'bananas') // {name: 'bananas', quantity: 0} // 稀疏数组 [0, 1, , , , 5].findLast((item) => item === undefined) // undefined // 类数组对象 const arrayLike = { 0: 0, 'foo': 'fooVal', 1: 7.3, 2: 2, length: 3, } Array.prototype.findLast.call(arrayLike, (x) => Number.isInteger(x)) // '2'
- 不会改变被调用的数组,提供
Array.prototype.findLastIndex()
语法:
arr.findLastIndex(callbackFn, thisArg)
描述: 反向迭代数组,并返回满足提供的
callbackFn
函数的第一个元素的索引。如果没有找到对应元素,则返回undefined
。- 不会改变被调用的数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度会被保存。callbackFn
不会访问超出数组初始长度的任何元素。- 对于已经访问过的索引重新赋值不会再次调用
callbackFn
。 - 如果
callbackFn
更改了数组中现有的、尚未访问的元素,传递给callbackFn
的值将是该元素被访问时的值。被删除的元素被视为undefined
。
- 对于稀疏数组,未赋值的空槽(
empty
元素)当作undefined
处理。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。
参数:
callbackFn
:数组中的每个元素执行的回调函数,该函数应该返回一个Truthy
(真值)来表示已经找到了匹配的元素。该函数接收以下参数:element
:数组中当前正在处理的元素。index
:正在处理的元素在数组中的索引。array
:调用了findLastIndex()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。
const inventory = [ { name: 'apples', quantity: 2 }, { name: 'bananas', quantity: 0 }, { name: "cherries", quantity: 5 }, ] inventory.findLastIndex(({ name }) => name === 'bananas') // 1 // 稀疏数组 [0, 1, , , , 5].findLastIndex((item) => item === undefined) // 4 // 类数组对象 const arrayLike = { 0: 0, 'foo': 'fooVal', 1: 7.3, 2: 2, length: 3, } Array.prototype.findLastIndex.call(arrayLike, (x) => Number.isInteger(x)) // '2'
- 不会改变被调用的数组,提供
添加、删除、替换方法
Array.prototype.concat()
语法:
arr.concat(value0, value1, /* … ,*/ valueN)
描述: 用于合并两个或多个数组。不会更改现有数组,而是返回一个新数组。
- 不会改变原数组的长度,不会改变原数组,会返回一个新的浅拷贝数组。
- 对于稀疏数组,会保留空槽(
empty
元素)。 - 对于类数组对象
- 如果
this
值不是数组,它会被转换为一个对象,然后以与concat()
的参数相同的方式处理。 - 仅在
Symbol.isConcatSpreadable
被设置为真值(例如,true
)时,才会将类数组对象视作数组。
- 如果
let a = [1, 2] let b = ['a', 'b'] let c = ['x', 'y'] a.concat(b, c) // [1, 2, 'a', 'b', 'x', 'y'] // 稀疏数组 [1, , 3].concat([4, 5]) // [1, empty, 3, 4, 5] // 类数组对象 const arrayLike01 = { 0: 'a', 1: 'b', length: 2, } Array.prototype.concat.call(arrayLike01, 2, 3) // [{ 0: 'a', 1: 'b', length: 2 }, 2, 3] const arrayLike02 = { 0: 'a', 1: 'b', length: 2, [Symbol.isConcatSpreadable]: true, } Array.prototype.concat.call(arrayLike02, 2, 3) // ['a', 'b', 2, 3]
Array.prototype.push()
语法:
arr.push(element0, element1, /* … ,*/ elementN)
描述: 将指定的元素添加到数组的末尾,并返回新的数组长度。
- 会改变原数组的长度,会改变原数组,返回新的数组长度。
- 对于类数组对象:
- 首先,会读取
this
的length
属性。 - 然后,它将
this
的每个索引从length
开始设置,并将参数传递给push()
。 - 最后,它将
length
设置成之前的长度加上已添加元素的数量。
- 首先,会读取
let arr1 = [1, 2] arr1.push('a', 'b') // 返回新的数组长度为 4 console.log(arr1) // [1, 2, 'a', 'b'] let arr2 = ['x', 'y'] arr2.push(...arr1) // 返回新的数组长度为 6 console.log(arr2) // ['x', 'y', 1, 2, 'a', 'b'] // 类数组对象 const arrayLike = { length: 3, unrelated: 'foo', 2: 4, } Array.prototype.push.call(arrayLike, 1, 2) // 返回新的数组长度为 5 console.log(arrayLike)// {'2': 4, '3': 1, '4': 2, length: 5, unrelated: 'foo'}
Array.prototype.pop()
语法:
arr.pop()
描述: 从数组中删除最后一个元素,并返回该元素的值(当数组为空时返回
undefined
)。- 会改变原数组的长度,会改变原数组。
- 对于类数组对象,会读取
this
上的length
属性。如果length
属性为不存在、负数、undefined
或者0
,会被再次设置为0
。否则,返回并删除位于length - 1
处的属性。
let arr1 = ['a', 'b', 'c'] arr1.pop() // 返回被删除的元素为 'c' console.log(arr1) // ['a', 'b'] const arrayLike = { length: 3, unrelated: 'foo', 2: 'b', } Array.prototype.pop.call(arrayLike) // 返回被删除的元素为 'b' console.log(arrayLike) // { length: 2, unrelated: 'foo' } const plainObj = {} Array.prototype.pop.call(plainObj) // 返回被删除的元素为 undefined console.log(plainObj) // { length: 0 }
Array.prototype.shift()
语法:
arr.shift()
描述: 从数组中删除第一个元素,并返回该元素的值。(当数组为空时返回
undefined
)。- 会改变原数组的长度,会改变原数组。
- 对于类数组对象,会读取
this
上的length
属性。如果length
属性为不存在、负数、undefined
或者0
,会被再次设置为0
。否则,返回0
处的属性,其余属性向左移动1
。length
属性递减1
。
let arr1 = ['a', 'b', 'c'] arr1.shift() // 返回被删除的元素为 'a' console.log(arr1) // ['b', 'c'] const arrayLike = { length: 3, unrelated: 'foo', 2: 'b', } Array.prototype.shift.call(arrayLike) // 返回被删除的元素为 undefined ,因为是一个空槽 console.log(arrayLike) // {1: 'b', length: 2, unrelated: 'foo'} const plainObj = {} Array.prototype.shift.call(plainObj) // 返回被删除的元素为 undefined console.log(plainObj) // { length: 0 }
Array.prototype.unshift()
语法:
arr.unshift(element0, element1, /* … ,*/ elementN)
描述: 将指定元素添加到数组的开头,并返回数组的新长度。
- 会改变原数组的长度,会改变原数组。
- 对于类数组对象:
- 首先,会读取
this
的length
属性。 - 然后,它将
0
到length - 1
范围内的所有属性按参数数量右移,并将每个索引从0
开始,并将参数传递给unshift()
。 - 最后,它将
length
设置为之前的长度加上前置元素的数量。
- 首先,会读取
let arr1 = ['a', 'b', 'c'] arr1.unshift('x') // 返回数组长度为 4 console.log(arr1) // ['x', 'a', 'b', 'c'] const arrayLike = { length: 3, unrelated: 'foo', 2: 'b', } Array.prototype.unshift.call(arrayLike, 1, 2) // 返回数组长度为 5 console.log(arrayLike) // { 0: 1, 1: 2, 4: 'b', length: 5, unrelated: 'foo' } const plainObj = {} Array.prototype.unshift.call(plainObj, 1, 2) // 返回数组长度为 2 console.log(plainObj) // { 0: 1, 1: 2, length: 2 }
Array.prototype.splice()
语法:
arr.splice(start, deleteCount, item1, ..., itemN)
描述: 从给定索引(
start
)开始移除指定数量(deleteCount
)元素,可以在相同索引处插入给定元素(item1, ..., itemN
),返回包含了删除元素的数组。- 会改变原数组的长度,会改变原数组,返回包含了删除元素的数组。
- 对于稀疏数组,如果删除的部分是空槽(
empty
元素),则返回的数组也是空槽(empty
元素)。 - 对于类数组对象,会读取
this
的length
属性,会读取所需的整数键属性并将其写入新数组。
参数:
start
:表示要开始改变数组的位置,从0
开始索引,会被转换为整数。- 如果 start < 0,使用 start + array.length。
- 如果
start < 0
,则从数组末尾开始计数(即start + array.length
)。 - 如果
start < -array.length
,则使用0
。 - 如果
start >= array.length
,则不会删除任何元素,该方法表现为添加所提供的元素。 - 如果
start
被省略(即,调用splice()
时,不传参),则不会删除任何元素。 - 如果
start
未undefined
,会被转换为0
。
deleteCount
:可选值。表示从start
开始删除的元素数量。- 如果
deleteCount
被省略,或者其值大于或者等于start
指定位置到数组末尾的元素数量,从start
到数组末尾的所有元素将被删除。 - 如果
deleteCount
是0
或者负数,则不会删除元素。 - 如果需要传递任何
itemN
参数,则应该设置deleteCount
为Infinity
值,以删除start
之后的所有元素。显示的设置为undefined
,会被转换为0
。
- 如果
item1, …, itemN
:可选值。从start
开始要加入到数组中的元素。如果不指定任何元素,splice()
将只从数组中删除元素。
let arr = ['a', 'b', 'c'] // 从给定索引 2 开始移除 0 个元素,并插入 'd' arr.splice(2, 0, 'd') // 返回删除元素的数组为 [] console.log(arr) // ['a', 'b', 'd', 'c'] // 从给定索引 3 开始移除 1 个元素 arr.splice(3, 1) // 返回删除元素的数组为 ['c'] console.log(arr) // ['a', 'b', 'd'] // 从给定索引 2 开始移除 1 个元素,并插入 'c' arr.splice(2, 1, 'c') // 返回删除元素的数组为 ['d'] console.log(arr) // ['a', 'b', 'c'] // 从给定索引 -2 (即,索引为 1)开始移除 1 个元素 arr.splice(-2, 1) // 返回删除元素的数组为 ['b'] console.log(arr) // ['a', 'c'] // 从给定索引 1 开始移除之后的所有元素 arr.splice(1) // 返回删除元素的数组为 ['c'] console.log(arr) // ['a'] // 稀疏数组 let sparseArr = [1, , 3, 4, , 6] // 从给定索引 1 开始移除 2 个元素 sparseArr.splice(1, 2) // 返回删除元素的数组为 [empty, 3] console.log(sparseArr) // [1, 4, , 6] // 类数组对象 const arrayLike = { length: 3, unrelated: 'foo', 0: 5, 2: 4, } Array.prototype.splice.call(arrayLike, 0, 1, 2, 3) // 返回删除元素的数组为 [5] console.log(arrayLike) // { 0: 2, 1: 3, 3: 4, length: 4, unrelated: 'foo' }
Array.prototype.toSpliced()
语法:
arr.toSpliced(start, deleteCount, item1, ..., itemN)
描述: 从给定索引(
start
)开始移除指定数量(deleteCount
)元素,可以在相同索引处插入给定元素(item1, ..., itemN
),返回一个新数组。- 是
splice()
方法对应的复制版本。 - 不会改变原数组的长度,不会改变原数组,会返回一个新的浅拷贝数组。
- 对于稀疏数组,原数组的空槽(
empty
元素),在新数组中被替换成undefined
。
let arr = ['a', 'b', 'c'] // 从给定索引 2 开始移除 0 个元素,并插入 'd' arr.toSpliced(2, 0, 'd') // 返回新数组为 ['a', 'b', 'd', 'c'] // 从给定索引 3 开始移除 1 个元素 arr.toSpliced(3, 1) // 返回新数组为 ['a', 'b', 'd'] // 从给定索引 2 开始移除 1 个元素,并插入 'c' arr.toSpliced(2, 1, 'c') // 返回新数组为 ['a', 'b', 'c'] // 从给定索引 -2 (即,索引为 1)开始移除 1 个元素 arr.toSpliced(-2, 1) // 返回新数组为 ['a', 'c'] // 从给定索引 1 开始移除之后的所有元素 arr.toSpliced(1) // 返回新数组为 ['a'] // 稀疏数组 let sparseArr = [1, , 3, 4, , 6] // 从给定索引 1 开始移除 2 个元素 sparseArr.toSpliced(1, 2) // 返回新数组为 [1, 4, undefined, 6] // 类数组对象 const arrayLike = { length: 3, unrelated: 'foo', 0: 5, 2: 4, } Array.prototype.toSpliced.call(arrayLike, 0, 1, 2, 3) // 返回新数组为 [2, 3, undefined, 4]
- 是
数组元素提取与替换
Array.prototype.at()
语法:
arr.at(index)
描述: 返回数组中给定索引匹配
index
的元素。index
为负数则从数组中的最后一个元素开始倒数。- 如果
index < -arr.length
或index >= arr.length
,则返回undefined
。
let arr = ['a', 'b', 'c'] arr.at(0) // 'a' arr.at(-1) // 'c' // 稀疏数组 let sparseArr = [1, , 3, 4, , 6] sparseArr.at(1) // undefined // 类数组对象 const arrayLike = { length: 3, unrelated: 'foo', 0: 'a', 2: 'b', } Array.prototype.at.call(arrayLike, -1) // 'b'
- 如果
Array.prototype.slice()
语法:
arr.slice(start, end)
描述: 返回一个新的数组对象,包含从索引
start
到end
(不包含) 的原数组的元素的浅拷贝。- 原始数组不会被改变,会返回一个新的浅拷贝数组。
- 对于稀疏数组,如果提取的部分是空槽(
empty
元素),则返回的数组也是空槽(empty
元素)。 - 对于类数组对象,会读取
this
的length
属性,然后从start
到end
读取整数键属性,并将它们定义在一个新创建的数组中。
参数:
start
:提取起始处的索引(从0
开始),会转换为整数。- 如果
start < 0
,则从数组末尾开始计数(即start + array.length
)。 - 如果
start < -arr.length
或者start
省略,则使用0
。 - 如果
start >= arr.length
,则不提取任何元素。
- 如果
end
:提取终止处的索引(从0
开始),会转换为整数。提取不包含end
位置的元素。- 如果
end < 0
,则从数组末尾开始计数(即end + array.length
)。 - 如果
end < -arr.length
或者end
省略,则使用0
。 - 如果
end >= arr.length
,则使用arr.length
,提取所有元素直到末尾。 - 如果
end <= start
,则不提取任何元素。
- 如果
let arr1 = ['a', 'b', 'c'] arr1.slice(0) // ['a', 'b', 'c'] arr1.slice(3) // [] arr1.slice(-3) // ['b', 'c'] arr1.slice(0, 1) // ['a'] arr1.slice(0, -2) // ['a'] arr1.slice(-2, -2) // [] let arr2 = [{ color: 'red' }, 'foo', 1] let arr3 = arr2.slice(0, 1) // [{ color: 'red' }] arr3[0].color = 'yellow' console.log(arr2) // [{ color: 'yellow' }, 'foo', 1] console.log(arr3) // [{ color: 'yellow' }] // 稀疏数组 [1, , 3, 4, , 6].slice(1, 3) // [empty, 3] // 类数组对象 const arrayLike = { length: 3, unrelsliceed: 'foo', 0: 'a', 2: 'b', } Array.prototype.slice.call(arrayLike, 1, 3) // [empty, 'b']
Array.prototype.with()
语法:
arr.with(index, value)
描述: 返回一个指定索引
index
处的值被新值value
替换的新数组。- 原始数组不会被改变,会返回一个新的浅拷贝数组。
- 对于稀疏数组,原数组的空槽(
empty
元素),在新数组中被替换成undefined
。 - 对于类数组对象,会读取
this
的length
属性,之后读取this
上的每个整数键并写入到新数组中,同时value
会被写入指定的index
。
参数:
index
:要修改的数组索引(从0
开始),将会转换为整数。- 如果
index < 0
,则从数组末尾开始计数(即index + array.length
)。 - 如果规范化后的索引超出数组边界(
index > arr.length
或index < -arr.length
),会抛出RangeError
。
- 如果
value
:要分配给指定索引的任何值。
let arr1 = ['a', 'b', 'c'] arr1.with() // [undefined, 'b', 'c'] arr1.with(0, 'x') // ['x', 'b', 'c'] let arr2 = [{ color: 'red' }, 'foo', 1] let arr3 = arr2.with(1, 'bar') // [{ color: 'red' }] arr3[0].color = 'yellow' console.log(arr2) // [{ color: 'yellow' }, 'foo', 1] console.log(arr3) // [{ color: 'yellow' }, 'bar', 1] // 稀疏数组 // [1, , 3, 4, , 6].with(0, 2) // [2, undefined, 3, 4, undefined, 6] // 类数组对象 const arrayLike = { length: 3, unrelwithed: 'foo', 0: 'a', 2: 'b', } Array.prototype.with.call(arrayLike, 0, 1) // [1, undefined, 'b']
排序方法
Array.prototype.reverse()
语法:
arr.reverse()
描述: 反转数组中元素的位置,改变了数组,并返回该数组的引用。
- 会改变原数组,返回对同一数组的引用。
- 对于稀疏数组,空槽(
empty
元素)将以空槽的形式被复制到它们各自的新索引中。 - 对于类数组对象,会读取
this
的length
属性。然后,它访问0
和length / 2
之间的每个索引,并交换两端对应的两个索引,并在必要时,删除某些属性。
let arr = ['a', 'b', 'c'] let arrReverse = arr.reverse() console.log(arrReverse) // ['c', 'b', 'a'] console.log(arr) // ['c', 'b', 'a'] // 稀疏数组 [1, , 3, 4, , 6].reverse() // [6, empty, 4, 3, empty, 1] // 类数组对象 const arrayLike = { length: 3, unrelreverseed: 'foo', 2: 'b', } Array.prototype.reverse.call(arrayLike) // {0: 'b', length: 3, unrelreverseed: 'foo'} // 索引 2 被删除,因为原本的数据中索引 0 不存在
Array.prototype.toReversed()
语法:
arr.toReversed()
描述: 反转原数组中元素的位置,并返回新数组。
- 是
reverse()
方法对应的复制版本。 - 不会改变原数组,会返回一个新的浅拷贝数组。
- 对于稀疏数组,原数组的空槽(
empty
元素),在新数组中被替换成undefined
。
let arr1 = ['a', 'b', 'c'] let arr1ToReversed = arr1.toReversed() console.log(arr1ToReversed) // ['c', 'b', 'a'] console.log(arr1) // ['a', 'b', 'c'] let arr2 = [{ color: 'red' }, 'foo', 1] let arr2ToReversed = arr2.toReversed() // [{ color: 'red' }] arr2ToReversed[2].color = 'yellow' console.log(arr2ToReversed) // [1, 'foo', { color: 'yellow' }] console.log(arr2) // [{ color: 'red' }, 'foo', 1] // 稀疏数组 [1, , 3, 4, , 6].toReversed() // [6, undefined, 4, 3, undefined, 1] // 类数组对象 const arrayLike = { length: 3, unreltoReverseded: 'foo', 2: 'b', } Array.prototype.toReversed.call(arrayLike) // ['b', undefined, undefined] // '0' 和 '1' 两个索引不存在,所以它们会变成 undefined
- 是
Array.prototype.sort()
语法:
arr.sort(compareFn)
描述: 对原数组的元素进行排序,并返回对相同数组的引用。
- 会改变原数组,返回对同一数组的引用。
- 如果未提供
compareFn
:所有非
undefined
的数组元素都会被转换为字符串,并按照UTF-16
码元顺序比较字符串进行排序。在 UTF-16 中,Unicode 字符超出
\uFFFF
的范围会被编码为两个代理码元(surrogate code unit),码位的范围是\uD800
到\uDFFF
。每个码位的值都会被单独考虑进行比较。因此,由代理对\uD855\uDE51
组成的字符将排在字符\uFF3A
的前面。所有的
undefined
元素都会被排序到数组的末尾。
- 如果提供了
compareFn
:所有非
undefined
的数组元素都会按照比较函数的返回值进行排序。compareFn(a, b) > 0
,则a
在b
后(如[b, a]
)compareFn(a, b) < 0
,则a
在b
前(如[a, b]
)compareFn(a, b) === 0
,则保持a
和b
原有顺序
所有的
undefined
元素都会被排序到数组的末尾,并且不调用compareFn
。
- 对于稀疏数组,空槽(
empty
元素)会被移动到数组的末尾,并始终排在所有undefined
元素的后面。 - 对于类数组对象,会读取
this
的length
属性。然后收集在0
到length - 1
范围内所有已存在的整数键属性,对它们进行排序,然后写回。如果范围内存在缺失的属性,则相应的尾随属性将被删除,好像不存在的属性被排序到末尾一样。
let stringArr = ['Blue', 'Humpback', 'Beluga'] let numberArr = [40, 1, 5, 200] let numericStringArr = ['80', '9', '700'] let mixedNumericArr = ['80', '9', '700', 40, 1, 5, 200] function compareNumbers(a, b) { return a - b } stringArr.sort() // ['Beluga', 'Blue', 'Humpback'] numberArr.sort() // [1, 200, 40, 5] numberArr.sort(compareNumbers) // [1, 5, 40, 200] numericStringArr.sort() // ['700', '80', '9'] numericStringArr.sort(compareNumbers) // ['9', '80', '700'] mixedNumericArr.sort() // [1, 200, 40, 5, '700', '80', '9'] mixedNumericArr.sort(compareNumbers) // [1, 5, '9', 40, '80', 200, '700'] // 稀疏数组 ['a', 'c', , 'b'].sort() // ['a', 'b', 'c', empty] [, undefined, 'a', 'b'].sort() // ['a', 'b', undefined, empty] // 类数组对象 const arrayLike = { length: 3, unrelated: 'foo', 0: 5, 2: 4, } Array.prototype.sort.call(arrayLike) // {0: 4, 1: 5, length: 3, unrelated: 'foo'}
Array.prototype.toSorted()
语法:
arr.toSorted(compareFn)
描述: 对原数组的元素进行排序,并返回新数组。
- 是
sort()
方法的复制方法版本。 - 不会改变原数组,会返回一个新的浅拷贝数组。
- 对于稀疏数组,原数组的空槽(
empty
元素),在新数组中被替换成undefined
。
let stringArr = ['Blue', 'Humpback', 'Beluga'] let numberArr = [40, 1, 5, 200] let numericStringArr = ['80', '9', '700'] let mixedNumericArr = ['80', '9', '700', 40, 1, 5, 200] function compareNumbers(a, b) { return a - b } stringArr.toSorted() // ['Beluga', 'Blue', 'Humpback'] numberArr.toSorted() // [1, 200, 40, 5] numberArr.toSorted(compareNumbers) // [1, 5, 40, 200] numericStringArr.toSorted() // ['700', '80', '9'] numericStringArr.toSorted(compareNumbers) // ['9', '80', '700'] mixedNumericArr.toSorted() // [1, 200, 40, 5, '700', '80', '9'] mixedNumericArr.toSorted(compareNumbers) // [1, 5, '9', 40, '80', 200, '700'] // 稀疏数组 ['a', 'c', , 'b'].toSorted() // ['a', 'b', 'c', undefined] [, undefined, 'a', 'b'].toSorted() // ['a', 'b', undefined, undefined] // 类数组对象 const arrayLike = { length: 3, unrelated: 'foo', 0: 5, 2: 4, } Array.prototype.toSorted.call(arrayLike) // [4, 5, undefined]
- 是
迭代方法
Array.prototype.forEach()
语法:
arr.forEach(callbackFn, thisArg)
描述: 按索引升序地为数组中的每个元素调用一次提供的
callbackFn
函数,forEach()
总是返回undefined
。- 不会改变原数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度已经被保存。因此:callbackFn
不会访问超出数组初始长度的任何元素。- 已经访问过的索引的更改不会导致
callbackFn
再次调用。 - 如果
callbackFn
更改了数组中已经存在但尚未访问的元素,则传递给callbackFn
的值将是在访问该元素时的值。已经被删除的元素不会被访问。
- 除非抛出异常,否则没有办法停止或中断
forEach()
循环。 forEach()
期望callbackFn
是一个同步函数,不会等待Promise
兑现。- 对于稀疏数组,空槽(
empty
元素)不会被调用。 - 对于类数组对象,读取
this
的length
属性,然后访问每个整数索引。
参数:
callbackFn
:数组中每个元素执行的函数。该函数接收以下参数:element
:数组中正在处理的当前元素。index
:数组中正在处理的当前元素的索引。array
:调用了forEach()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。使用箭头函数表达式来传入函数参数,thisArg
参数会被忽略,因为箭头函数在词法上绑定了this
值。
const arr = ['a', 'b', 'c'] arr.forEach((element) => console.log(element)) // a // b // c // 稀疏数组 const sparseArr = [1, 3 /* empty */, , 7] let numCallbackRuns = 0 sparseArr.forEach((element) => { console.log({ element }) numCallbackRuns++ }) console.log('numCallbackRuns : ', numCallbackRuns) // {element: 1} // {element: 3} // {element: 7} // numCallbackRuns : 3 // 类数组对象 const arrayLike = { length: 3, 0: 2, 1: 3, 2: 4, } Array.prototype.forEach.call(arrayLike, (x) => console.log(x)) // 2 // 3 // 4
- 不会改变原数组,提供
Array.prototype.map()
语法:
arr.map(callbackFn, thisArg)
描述: 创建一个新数组,数组元素由原数组中每个元素调用提供的回调函数
callbackFn
的返回值组成。- 不会改变原数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度已经被保存。因此:callbackFn
不会访问超出数组初始长度的任何元素。- 已经访问过的索引的更改不会导致
callbackFn
再次调用。 - 如果
callbackFn
更改了数组中已经存在但尚未访问的元素,则传递给callbackFn
的值将是在访问该元素时的值。已经被删除的元素不会被访问。
- 对于稀疏数组,空槽(
empty
元素)的索引在返回的数组中仍然为空槽,并且回调函数不会对它们进行调用。 - 对于类数组对象,读取
this
的length
属性,然后访问每个整数索引。
参数:
callbackFn
:原数组中每个元素执行的函数,返回值作为一个元素被添加为新数组中。该函数接收以下参数:element
:数组中正在处理的当前元素。index
:数组中正在处理的当前元素的索引。array
:调用了map()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。
let numbersArr1 = [1, 4, 9] let roots1 = numbersArr1.map((num) => Math.sqrt(num)) console.log(numbersArr1) // [1, 4, 9] console.log(roots1) // [ 1, 2, 3] // 稀疏数组 let sparseArr = [1, , 3].map((x, index) => { console.log(`Visit ${index}`) return x * 2 }) console.log(sparseArr) // Visit 0 // Visit 2 // [2, empty, 6] const numbersArr2 = [1, 2, 3, 4] const filteredNumbers = numbersArr2.map((num, index) => { if (index < 3) { return num } }) console.log(numbersArr2) // [1, 2, 3, 4] console.log(filteredNumbers) // [1, 2, 3, undefined] // 类数组对象 const arrayLike = { length: 3, 0: 2, 1: 3, 2: 4, } Array.prototype.map.call(arrayLike, (x) => x ** 2) // [4, 9, 16]
- 不会改变原数组,提供
Array.prototype.filter()
语法:
arr.filter(callbackFn, thisArg)
描述: 用于过滤数组成员,返回满足条件的数组元素的浅拷贝。如果没有元素满足条件,则返回一个空数组。
- 不会改变原数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度已经被保存。因此:callbackFn
不会访问超出数组初始长度的任何元素。- 已经访问过的索引的更改不会导致
callbackFn
再次调用。 - 如果
callbackFn
更改了数组中已经存在但尚未访问的元素,则传递给callbackFn
的值将是在访问该元素时的值。已经被删除的元素不会被访问。
- 对于稀疏数组,
filter()
会跳过空槽(empty
元素)。 - 对于类数组对象,读取
this
的length
属性,然后访问每个整数索引。
参数:
callbackFn
:数组中的每个元素执行的函数。该函数应该返回一个Truthy
(真值)以将元素保留在结果数组中。该函数接收以下参数:element
:数组中正在处理的当前元素。index
:数组中正在处理的当前元素的索引。array
:调用了filter()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。
let arr1 = [12, 5, 8, 130, 44] let filterArr1 = arr1.filter((element) => element >= 10) console.log(filterArr1) // [12, 130, 44] console.log(arr1) // [12, 5, 8, 130, 44] // 稀疏数组 let sparseArr = [1, , undefined].filter((element) => element !== 2) console.log(sparseArr) // [1, undefined] // 类数组对象 const arrayLike = { length: 3, 0: 'a', 1: 'b', 2: 'c', } Array.prototype.filter.call(arrayLike, (x) => x <= 'b') // ['a', 'b']
- 不会改变原数组,提供
Array.prototype.every()
语法:
arr.every(callbackFn, thisArg)
描述: 测试一个数组内的所有元素是否都能通过指定函数
callbackFn
的测试,返回一个布尔值。- 不会改变原数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度已经被保存。因此:callbackFn
不会访问超出数组初始长度的任何元素。- 已经访问过的索引的更改不会导致
callbackFn
再次调用。 - 如果
callbackFn
更改了数组中已经存在但尚未访问的元素,则传递给callbackFn
的值将是在访问该元素时的值。已经被删除的元素不会被访问。
- 对于稀疏数组,空槽(
empty
元素)不会执行callbackFn
。 - 对于类数组对象,读取
this
的length
属性,然后访问每个整数索引,直到到达末尾或callbackFn
返回false
。
参数:
callbackFn
:数组中的每个元素执行的函数。该函数应该返回一个Truthy
(真值)表示元素通过测试。该函数接收以下参数:element
:数组中正在处理的当前元素。index
:数组中正在处理的当前元素的索引。array
:调用了every()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。
const isSubset = (array1, array2) => array2.every((element) => array1.includes(element)) isSubset([1, 2, 3, 4, 5, 6, 7], [5, 7, 6]) // true let arr = [1, 2, 3, 4] arr.every((elem, index, arr) => { arr[index + 1]-- console.log(`[${arr}][${index}] -> ${elem}`) return elem < 2 }) // 循环会迭代 3 次 // 没有修改的情况下只会迭代 2 次 // 第 1 次迭代:[1,1,3,4][0] -> 1 // 第 2 次迭代:[1,1,2,4][1] -> 1 // 第 3 次迭代:[1,1,2,3][2] -> 2 // 稀疏数组 [1, , 3].every((element) => element !== undefined) // true // 类数组对象 const arrayLike = { length: 3, 0: 'a', 1: 'b', 2: 'c', } Array.prototype.every.call(arrayLike, (x) => typeof x === 'string') // true
- 不会改变原数组,提供
Array.prototype.some()
语法:
arr.some(callbackFn, thisArg)
描述: 测试数组中是否至少有一个元素通过了由提供的函数
callbackFn
实现的测试。如果在数组中找到一个元素,使得提供的函数返回true
,则返回true
;否则返回false
。- 不会改变原数组,提供
callbackFn
的函数可以更改原数组。 some()
方法如果找到满足条件的元素,将会立即返回true
并停止遍历数组。- 对于空数组,任何条件下它都返回
false
。 - 在第一次调用
callbackFn
之前,数组的长度已经被保存。因此:callbackFn
不会访问超出数组初始长度的任何元素。- 已经访问过的索引的更改不会导致
callbackFn
再次调用。 - 如果
callbackFn
更改了数组中已经存在但尚未访问的元素,则传递给callbackFn
的值将是在访问该元素时的值。已经被删除的元素不会被访问。
- 对于稀疏数组,空槽(
empty
元素)不会执行callbackFn
。 - 对于类数组对象,读取
this
的length
属性,然后访问每个整数索引,直到到达末尾或callbackFn
返回true
。
参数:
callbackFn
:数组中的每个元素执行的函数。该函数应该返回一个Truthy
(真值)表示元素通过测试。该函数接收以下参数:element
:数组中正在处理的当前元素。index
:数组中正在处理的当前元素的索引。array
:调用了every()
的数组本身。
thisArg
:执行callbackFn
时用作this
的值。
[12, 5, 8, 1, 4].some((x) => x > 10) // true // 稀疏数组 [1, undefined, 1].some((x) => x !== 1) // true // 类数组对象 const arrayLike = { length: 3, 0: 'a', 1: 'b', 2: 'c', } Array.prototype.some.call(arrayLike, (x) => typeof x === 'number') // false
- 不会改变原数组,提供
归并方法
Array.prototype.reduce()
/Array.prototype.reduceRight()
语法:
arr.reduce(callbackFn, initialValue)
/arr.reduceRight(callbackFn, initialValue)
描述: 对数组中的每个元素按序执行一个提供的
reducer
函数,每一次运行reducer
会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。- 不会改变原数组,提供
callbackFn
的函数可以更改原数组。 - 在第一次调用
callbackFn
之前,数组的长度已经被保存。因此:callbackFn
不会访问超出数组初始长度的任何元素。- 已经访问过的索引的更改不会导致
callbackFn
再次调用。 - 如果
callbackFn
更改了数组中已经存在但尚未访问的元素,则传递给callbackFn
的值将是在访问该元素时的值。已经被删除的元素不会被访问。
- 对于稀疏数组,空槽(
empty
元素)不会执行callbackFn
。 - 对于类数组对象,读取
this
的length
属性,然后访问每个整数索引。 reduce()
与reduceRight()
之间的区别reduce()
方法从左至右遍历reduceRight()
方法从右至左遍历
参数:
callbackFn
:为数组中每个元素执行的函数。其返回值将作为下一次调用callbackFn
时的accumulator
参数。对于最后一次调用,返回值将作为reduce()
的返回值。该函数接收以下参数:accumulator
:上一次调用callbackFn
的结果。在第一次调用时,如果指定了initialValue
则为指定的值,否则为array[0]
的值。currentValue
:当前元素的值。在第一次调用时,如果指定了initialValue
,则为array[0]
的值,否则为array[1]
。currentIndex
:currentValue
在数组中的索引位置。在第一次调用时,如果指定了initialValue
则为0
,否则为1
。array
:调用了reduce()
的数组本身。
initialValue
:第一次调用回调时初始化accumulator
的值。- 如果指定了
initialValue
callbackFn
从 数组中的第一个值(对于reduceRight()
方法则为数组中的倒数第一个值) 作为currentValue
开始执行。
- 如果没有指定
initialValue
accumulator
初始化为数组中的第一个值(对于reduceRight()
方法则为数组中的倒数第一个值)callbackFn
从 数组中的第二个值(对于reduceRight()
方法则为数组中的倒数第二个值) 作为currentValue
开始执行。
- 如果数组只有一个元素(无论其位置如何)且没有提供
initialValue
,或者提供了initialValue
但数组为空,则直接返回该单个值,且callbackFn
不会被调用。 - 如果数组为空且没有提供
initialValue
(没有第一个值可以作为accumulator
返回),则会抛出TypeError
异常。
- 如果指定了
// 未提供 initialValue // 对于长度大于 1、等于 1 和 0 的数组,reduce 方法的不同表现 const getMax = (a, b) => Math.max(a, b) // 从索引 0 开始为数组中的每个元素调用回调函数 [1, 100].reduce(getMax, 50) // 100 [50].reduce(getMax, 10) // 50 // 仅为索引 1 处的元素调用回调函数 [1, 100].reduce(getMax) // 100 // 不调用回调函数 [50].reduce(getMax) // 50 [].reduce(getMax, 1) // 1 [].reduce(getMax) // TypeError // ============================== const array = [15, 16, 17, 18] function reducer(accumulator, currentValue, index) { const returns = accumulator + currentValue console.log( `accumulator: ${accumulator}, currentValue: ${currentValue}, index: ${index}, returns: ${returns}` ) return returns } array.reduce(reducer) // 66 // accumulator: 15, currentValue: 16, index: 1, returns: 31 // accumulator: 31, currentValue: 17, index: 2, returns: 48 // accumulator: 48, currentValue: 18, index: 3, returns: 66 // ============================== // reduce 与 reduceRight 之间的区别 const arr = ['1', '2', '3', '4', '5'] const left = arr.reduce((prev, cur) => prev + cur) const right = arr.reduceRight((prev, cur) => prev + cur) console.log(left) // '12345' console.log(right) // '54321' // ============================== // 数组去重 const myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'] const myArrayWithNoDuplicates = myArray.reduce((accumulator, currentValue) => { if (!accumulator.includes(currentValue)) { return [...accumulator, currentValue] } return accumulator }, []) console.log(myArrayWithNoDuplicates) // ['a', 'b', 'c', 'e', 'd'] // 展平嵌套数组 const flattened = [ [0, 1], [2, 3], [4, 5], ].reduce((accumulator, currentValue) => accumulator.concat(currentValue), []) // [0, 1, 2, 3, 4, 5] // ============================== // 稀疏数组:会跳过空槽(emtpy 元素),不会跳过 undefined 值 [1, 2, undefined, 4].reduce((a, b) => a + b) // NaN // ============================== // 类数组对象 const arrayLike = { length: 3, 0: 2, 1: 3, 2: 4, } Array.prototype.reduce.call(arrayLike, (x, y) => x + y) // 9
- 不会改变原数组,提供
数组扁平化
Array.prototype.flat()
语法:
arr.flat(depth)
描述: 创建一个新的数组,并根据指定深度
depth
递归地将所有子数组元素拼接到新的数组中。- 不会改变原数组,会返回一个新的浅拷贝数组。
- 如果待展开的数组是稀疏的,
flat()
方法会忽略其中的空槽(empty
元素)。例如,如果depth
是1
,那么根数组和第一层嵌套数组中的空槽都会被忽略,但在更深的嵌套数组中的空槽则会与这些数组一起保留。 - 对于类数组对象,读取
this
的length
属性,然后访问每个整数索引。如果元素不是数组,则直接将其附加到结果中。如果元素是数组,则根据depth
参数进行展开操作。
[1, 2, [3, 4]].flat() // [1, 2, 3, 4] [1, 2, [3, 4, [5, 6]]].flat() // [1, 2, 3, 4, [5, 6]] [1, 2, [3, 4, [5, 6]]].flat(2) // [1, 2, 3, 4, 5, 6] [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]].flat(Infinity) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 稀疏数组 [1, 2, , 4, 5].flat() // [1, 2, 4, 5] [1, , 3, ['a', , 'c']].flat() // [ 1, 3, 'a', 'c'] [1, , 3, ['a', , ['d', , 'e']]].flat() // [1, 3, 'a', ['d', empty, 'e']] [1, , 3, ['a', , ['d', , 'e']]].flat(2) // [1, 3, 'a', 'd', 'e'] // 类数组对象 const arrayLike = { length: 3, 0: [1, 2], // 嵌套的类数组对象不会被展平 1: { length: 2, 0: 3, 1: 4 }, 2: 5, } Array.prototype.flat.call(arrayLike) // [1, 2, { 0: 3, 1: 4, length: 2 }, 5]
Array.prototype.flatMap()
语法:
arr.flatMap(callbackFn, thisArg)
描述: 对数组中的每个元素应用给定的回调函数
callbackFn
,然后将结果展开一级,返回一个新数组。- 等价于在调用
map()
方法后再调用深度为1
的flat()
方法(arr.map(...args).flat()
),但比分别调用这两个方法稍微更高效一些。 - 对于稀疏数组,空槽(
empty
元素)不会执行callbackFn
,对于callbackFn
返回的空槽,flatMap
将忽略返回数组中的空槽。 - 对于类数组对象,会读取
this
的length
属性,然后访问每个整数索引。如果回调函数的返回值不是数组,则始终直接将其附加到结果数组的末尾。
参数:
callbackFn
:一个在数组的每个元素上执行的函数。函数应该返回一个包含新数组元素的数组,或是要添加到新数组中的单个非数组值。该函数接收以下参数:element
:数组中正在处理的当前元素。index
:数组中正在处理的当前元素的索引。array
:调用flatMap()
的当前数组。
thisArg
:可选值。在执行callbackFn
时用作this
的值。
const arr1 = ["it's Sunny in", '', 'California'] arr1.map((x) => x.split(' ')) // [["it's", 'Sunny', 'in'], [''],['California']] arr1.flatMap((x) => x.split(' ')) // ["it's", 'Sunny', 'in', '', 'California'] // 稀疏数组 [1, 2, , 4, 5].flatMap((x) => [x, x * 2]) // [1, 2, 2, 4, 4, 8, 5, 10] [1, 2, 3, 4].flatMap((x) => [, x * 2]) // [2, 4, 6, 8] // 类数组对象 const arrayLike = { length: 3, 0: 1, 1: 2, 2: 3, } Array.prototype.flatMap.call(arrayLike, (x) => [x, x * 2]) // [1, 2, 2, 4, 3, 6] Array.prototype.flatMap.call(arrayLike, (x) => ({ length: 1, 0: x, })) // [{0: 1, length: 1}, {0: 2, length: 1}, {0: 3, length: 1}]
- 等价于在调用