数组是值的有序集合,其中的值叫做元素,每个元素有一个数值表示的位置,叫做索引。JavaScript数组是无类型限制的,即数组中的元素可以是任意类型,同一数组的不同元素也可以是不同的类型。数组元素从第一个索引值0开始,到最大索引值4 294 967 294,也就是说数组可以包含4 294 967 294个元素。JavaScript数组是动态的,它们会按需增大或缩小,因此创建数组无需声明一个固定大小,也无需再大小变化时重新为它们分配空间。
数组从Array.prototype继承属性。
ES6增加了“定型数组”,与常规的数组不同,该数组具有固定长度和固定的数值元素类型,定型数组具有极高的性能,支持对二进制数据的字节级访问。
创建数组数组字面量
let empty = [] // 空数组
let primes = [1, 2, 3, 4, 5] // 同类型的数组
let array = [1.1, true , 'a', primes] // 不同类型的元素
数组字面量可以包含对象字面量或其他数组字面量:
let array = [ [ 1, { x: 1, y: 2 } ], [ 2, { x: 3, y: 4 } ] ]
扩展操作符
数组可以使用扩展操作符——...
在一个数组字面量中包含另一个数组的元素:
let a = [1, 2, 3]
let b = [0, ...a, 4] // b == [0, 1, 2, 3, 4]
扩展操作符适用于任何可迭代对象。字符串是可迭代对象,因此可以使用扩展操作符把任意字符串转换为单个字符的数组:
let digits = [...'0123456789']
console.log(digits) // 0,1,2,3,4,5,6,7,8,9
集合对象是可迭代的,因此要去除数组中的重复元素,一种便捷方式就先把数组转换为集合,然后在使用扩展操作符把这个集合转换回数组:
let o = [...'hello world']
let set = [...new Set(o)]
console.log(set.toString()) // h,e,l,o, ,w,r,d
Array()构造函数
构造函数可以传入参数,指定数组的长度。或者传入多个参数作为新数组的元素。
let a = new Array(10) // 指定长度为10
let a = new Array(1, 2, 3, 4, 'hello', true) // 传入的参数作为新数组的元素
Array.of()
Array.of()函数可以使其参数值作为数组元素来创建并返回新数组:
Array.of() // 空数组
Array.of(10) // [10]
Array.of(1, 2, 3) // [1, 2, 3]
Array.from()
Array.from(iterable)期待一个可迭代对象(Set、Map、类数组对象和字符串)作为参数,并返回包含该对象元素的新数组。
除了可以接收第一个参数以外,第二个是一个回调函数:
// 字符串
Array.from('foo')
// Array ["f", "o", "o"]
// 回调函数
Array.from('foo', (value) => {
console.log(value)
})
// f o o
// set集合
const set = new Set(['foo', 'bar', 'baz', 'foo'])
Array.from(set);
// [ "foo", "bar", "baz" ]
// map集合
const map = new Map([[1, 2], [2, 4], [4, 8]])
Array.from(map);
// [[1, 2], [2, 4], [4, 8]]
// 类数组对象
function f() {
return Array.from(arguments)
}
let array = f(1, 2, 3)
// [1, 2, 3]
添加和删除数组元素
给新索引赋值:
let a = []
a[0] = 'zero'
a[1] = 'one'
push()方法在数组末尾添加一个或多个元素:
let a = []
a.push('zero', 'one', 'two')
delete操作符删除数组元素:
let a = [1, 2, 3]
delete a[2]
a.length // 3,delete删除元素不修改数组长度
对数组元素使用delete操作符不会修改length属性,也不会把高索引位的元素向下移动来填充被删除属性的空隙,而splice()是一个可以插入、删除或替换数组元素的通用方法,通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容,此方法会改变原数组:
在指定索引位置添加一个元素:
const months = ['Jan', 'March', 'April', 'June']
months.splice(1, 0, 'Feb') // ["Jan", "Feb", "March", "April", "June"]
替换指定索引位置处的元素:
const months = ['Jan', 'March', 'April', 'June']
months.splice(4, 1, 'May') // ["Jan", "Feb", "March", "April", "May"]
迭代数组
array.entries()
entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对:
let str = [...'hello world']
for (let [index, value] of str.entries()) {
console.log(value)
}
forEach()
forEach((currentValue, index, array) => {}) 方法按升序为数组中含有效值的每一项执行一次回调函数,那些已删除或者未初始化的项将被跳过。
currentValue是指当前迭代的元素,index是当前迭代的索引,array是被循环的数组。
let str = [...'hello world']
str.forEach((currentValue, index, array) => {
console.log(currentValue)
})
数组方法
迭代器方法
map()
map()方法会给原数组中的每个元素都按顺序调用一次回调函数。回调函数每次执行后的返回值(包括 undefined)组合起来形成一个新数组。因为map()生成一个新数组,当你不打算使用返回的新数组却使用map是违背设计初衷的,要么使用forEach或者for-of替代。
let array = [1, 2, 3, 4, 5]
let dest = array.map((currentValue) => {
currentValue = currentValue * 2
return currentValue
})
filter()
filter() 方法创建一个新数组,该数组包含调用它的数组的子数组。回调函数用来测试数组的每个元素的函数,返回 true 表示该元素通过测试,保留该元素,false 则不保留。
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present']
const result = words.filter((word) => { return word.length > 6 }) // ["exuberant", "destruction", "present"]
find()和findIndex()
find()和findIndex()在找到第一个元素时停止迭代,find返回匹配的元素,findIndex返回匹配元素的索引值:
const words = [
'spray',
'limit',
'elite',
'exuberant',
'destruction',
'present'
]
const result = words.find((word) => {
return word.length > 6
})
// exuberant,一旦满足一次true,结束查询,并返回数组元素
const index = words.findIndex((word) => {
return word.length > 6
})
// 3,一旦满足一次true,返回数组元素的索引值
every()和some()
every()方法为数组中的每个元素执行一次回调函数,直到它找到一个会使回调返回 false 的元素。如果发现了一个这样的元素,every()方法将会立即返回 false。否则,回调函数会为每一个元素返回 true:
const words = [
'spray',
'limit',
'elite',
'exuberant',
'destruction',
'present'
]
const result = words.every((word) => {
return word.length > 6
})
// false,第一个元素——spray字符长度小于6,不满足条件,停止遍历
some() 为数组中的每一个元素执行一次回调函数,直到找到一个使得回调函数返回一个true。如果找到了这样一个值,some() 将会立即返回 true。否则,some() 返回 false:
const words = [
'spray',
'limit',
'elite',
'exuberant',
'destruction',
'present'
]
const result = words.some((word) => {
return word.length > 6
})
// true,函数找到一个符合字符长度大于6的元素,停止遍历
归并数组元素
reduce()和reduceRight()使我们指定的函数归并数组元素,最终产生一个值。有时候也称为注入或折叠。
reduce((accumulator, currentValue, currentIndex) => {}, initialValue)是低索引值向高索引值递增(升序),回调函数的第一个参数accumulator是累加之后的值,第二个参数currentValue是当前迭代的元素,第三个参数currentIndex是当前迭代的元素在数组的索引值。
如果reduce()提供了initialValue,accumulator的初始值为initialValue,currentValue取数组中的第一个值;如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。
let a = [1, 2, 3, 4, 5]
let result = a.reduce((accumulator, currentValue, currentIndex) => {
return accumulator + currentValue
}, 0) // 15
a.reduce((x, y) => x * y, 1) // 120
a.reduce((x, y) => (x > y) ? x : y) // 5
reduceRight((accumulator, currentValue, index) => {}, initialValue)是高索引值向低索引值递减(降序),回调函数的第一个参数accumulator是累加之后的值,第二个参数currentValue是当前迭代的元素,第三个参数currentIndex是当前迭代的元素在数组的索引值。
如果reduce()提供了initialValue,accumulator的初始值为initialValue;如果没有提供 initialValue,那么accumulator取数组中的最后一个值。
let a = [1, 2, 3, 4, 5]
let result = a.reduceRight((accumulator, currentValue, currentIndex) => {
return accumulator + currentValue
}, 0) // 15
打平数组
flag()方法用于创建并返回一个新数组,无参调用时,flag()会打平一级嵌套,如果打平更多层级,需要给方法传递数值参数:
let a = [1, 2, 3, [4, 5, 6, [7, 8, 9]]]
let b = a.flat() // 1级:[1, 2, 3, 4, 5, 6, [7, 8, 9]]
let c = a.flat(2) // 2级:[1, 2, 3, 4, 5, 6, 7, 8, 9]
flagMap()方法返回的数组会自动打平一级,a.flagMap()等同于a.map().flat():
let array = ["it's Sunny in", '', 'California']
array.map((value) => value.split(' ')) // [["it's","Sunny","in"],[""],["California"]]
array.flatMap((value) => value.split(' ')) // ["it's","Sunny","in", "", "California"]
// array.map()等同于array.map().flat()
array.map((value) => value.split(' ')).flat() // ["it's","Sunny","in", "", "California"]
添加数组
concat()方法创建并返回一个新数组,新数组包含原数组,以及传给concat()的参数。如果这些参数中有数组,则拼接的是它们的元素而非数组本身:
let a = [1, 2, 3]
let b = a.concat([4, 5], [6, 7]) // [1, 2, 3, 4, 5, 6, 7]
concat()创建并返回的新数组不会被打平:
let a = [1, 2, 3]
let b = a.concat(4, [5, [6, 7]]) // [1, 2, 3, 4, 5, [6, 7]]
concat()并不修改调用它的数组:
let a = [1, 2, 3]
let b = a.concat(4, 5)
console.log('b', b) // b (5) [1, 2, 3, 4, 5],创建新数组b
console.log('a', a) // a (3) [1, 2, 3],不修改数组a
实现栈和队列操作
push()
push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度:
const animals = ['pigs', 'goats', 'sheep']
animals.push('cows') // 4
animals.push('chickens', 'cats', 'dogs') // 7
push().apply()可以合并两个数组:
let vegetables = ['parsnip', 'potato']
let moreVegs = ['celery', 'beetroot']
// 将第二个数组融合进第一个数组
// 相当于 vegetables.push('celery', 'beetroot');
// Array.prototype.push.apply(vegetables, moreVegs)
vegetables.push.apply(vegetables, moreVegs) // ["parsnip", "potato", "celery", "beetroot"]
pop()
pop() 方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度:
const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato']
console.log(plants.pop()) // "tomato"
shift()
shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度:
const array = [1, 2, 3];
const firstElement = array.shift() // 1
unshift()
unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组):
const array = [1, 2, 3]
console.log(array.unshift(4, 5)) // 5
// [4, 5, 1, 2, 3]
数组切片
数组定义了几个处理连续区域的方法,即数组的提取、替换、填充和复制切片的方法。
slice()
slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
const animals = ['ant', 'bison', 'camel', 'duck', 'elephant']
console.log(animals.slice(2))
// ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4))
// ["camel", "duck"]
console.log(animals.slice(1, 5))
// ["bison", "camel", "duck", "elephant"]
console.log(animals.slice(-2))
// ["duck", "elephant"]
console.log(animals.slice(2, -1))
// ["camel", "duck"]
splice()
splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组:
const months = ['Jan', 'March', 'April', 'June']
months.splice(1, 0, 'Feb') // 在index为1处插入一个元素,["Jan", "Feb", "March", "April", "June"]
months.splice(4, 1, 'May') // 替换index为4处的元素为May,["Jan", "Feb", "March", "April", "May"]
months.splice(2, 2) // 删除索引值为[2, 3]的元素, ["Jan", "Feb", "May"]
fill()
第一个参数是替换的元素,第二个参数是其实索引,第三个是终止索引(不包括终止索引处的元素)。如果终止索引为负数,那么终止索引=数组长度-终止索引
;如果没有终止索引,那么将会替换到数组的最后一个元素为止。
const array = [1, 2, 3, 4]
console.log(array.fill(0, 2, -1)) // 终止索引为-1,则end为length-end,即end为3,因此替换index为2,但不包括终止索引3,
// [1, 2, 0, 0]
console.log(array.fill(5, 1)) // 没有终止索引,替换元素为5,从index为1开始直到最后一个元素
// [1, 5, 5, 5]
console.log(array.fill(6)) // 全部元素替换为6
// [6, 6, 6, 6]
数组到字符串的转换
join()方法把数组的所有元素转换为字符串,如果指定一个字符串参数,用于分隔结果字符串中的元素,如果不指定分隔符,则默认使用逗号:
let a = [1, 2, 3]
a.join() // "1,2,3"
a.join('-') // "1-2-3"
toString()方法与没有参数的join()方法一样:
let a = [1, 2, 3]
a.toString() // "1,2,3"