创建数组
let a = [5,6,7] // 字面量方式
let a = new Array() // 构造函数
let a = Array() // 可以省略 new
// 需要注意的是,将数字作为参数,会创建长度为2的空数组
let a = Array(2)
console.log(a) // [empty × 2]
静态方法
Array.of()将参数转换为数组实例
创建一个具有可变数量参数的新数组实例,而不考虑参数的数量和类型。
这个方法用于替代 ES6 之前常用的Array.prototype.slice.call(arguments)将arguments对象转换为数组的写法。
conconsole.log(Array.of(5)) // [5]
console.log(Array.of("hello", 5, function foo() { })) // ["hello", 5, ƒ]
Array.from()将类数组结构转换为数组实例
从一个类数组(可迭代对象 或者 有一个 length 属性和可索引属性的任意对象)对象创建一个新的,浅拷贝的数组实例。
arraylike想要转换成数组的伪数组对象或可迭代对象。mapFn如果指定了该参数,新数组中的每个元素会执行该回调函数。thisArg可选参数,执行回调函数mapFn时this对象。
// 从 String 生成数组
console.log(Array.from('foobar')) // ["f", "o", "o", "b", "a", "r"]
// 从 Set 生成数组
const set = new Set(['foo', 'bar', 'baz', 'foo'])
console.log(Array.from(set))// ["f", "o", "o", "b", "a", "r"]
// 从 Map 生成数组
const map = new Map([[1, 2], [2, 4], [4, 8]])
console.log(Array.from(map)) // [[1, 2], [2, 4], [4, 8]]
console.log(Array.from(map.keys())) // [1, 2, 4]
console.log(Array.from(map.values())) // [2, 4, 8]
// 从类数组对象(arguments)生成数组
function f() {
return Array.from(arguments)
}
console.log(f(1, 'foo', [6, 7])) // [1, "foo", [6, 7]]
实例方法
修改器方法(改变原数组)
pop()删除数组最后一项
从数组中删除最后一个元素,并返回该元素的值。
const colors = ['red','green','blue','orange']
console.log(colors.pop()) // orange
console.log(colors) // ["red", "green", "blue"]
const arr = []
console.log(arr.pop()) // undefined
push()数组末尾插入元素
将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
const colors = ['red', 'green']
console.log(colors.push('blue', 'orange')) // 4
console.log(colors) // ["red", "green", "blue", "orange"]
unshift()数组开头插入元素
将一个或多个元素添加到数组的开头,并返回该数组的新长度。
const arr = [1, 2, 3, 4, 5]
console.log(arr.unshift(6, 7))
console.log(arr) // [6, 7, 1, 2, 3, 4, 5]
shift()删除数组第一个元素
从数组中删除第一个元素,并返回该元素的值。
const arr = [1, 2, 3, 4, 5]
console.log(arr.shift()) // 1
const arr2 = []
console.log(arr2.shift()) // undefined
splice()添加/删除数组元素
通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。
start指定修改的开始位置(从0计数)。- 正数,超过
array.length,从数组末尾开始添加内容; - 负数,从数组末位开始的第几位(等价于
array.length-n); - 负数,绝对值大于数组长度,则表示开始位置为第 0 位。
- 正数,超过
deleteCount可选 整数,表示要移除的数组元素的个数。deleteCount大于等于start之后的元素的总数(array.length-start),则从start后面的元素都将被删除(含第start位);deleteCount被省略了,那么start之后数组的所有元素都会被删除;deleteCount是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。
item1, item2, ...可选 要添加进数组的元素,从start位置开始。如果不指定,则splice()将只删除数组元素。
//删除
let colors = ['red', 'green', 'blue', 'brown', 'orange']
let removed = colors.splice(1, 1)
console.log(colors) // ["red", "blue", "brown", "orange"]
let colors1 = ['red', 'green', 'blue', 'brown', 'orange']
let removed1 = colors1.splice(0, 8)
console.log(colors1) // [] deleteCount 大于 start ,所有元素都被删除
let colors2 = ['red', 'green', 'blue', 'brown', 'orange']
let removed2 = colors2.splice(0, 5)
console.log(colors2) // [] deleteCount 等于 start ,所有元素都被删除
let colors3 = ['red', 'green', 'blue', 'brown', 'orange']
let removed3 = colors3.splice(0)
console.log(colors3) // [] 省略 deleteCount ,所有元素都被删除
//插入
let colors = ['red']
let insert = colors.splice(0, 0, 'green', 'blue')
console.log(colors) // ["green", "blue", "red"]
let colors1 = ['red']
let insert1 = colors1.splice(5, 0, 'green', 'blue')
console.log(colors1) // ["red", "green", "blue"] start 大于 array.length ,数组末尾开始添加
let colors2 = ['red', 'green', 'blue']
let insert2 = colors2.splice(-2, 0, 'brown', 'orange')
console.log(colors2) // ["red", "brown", "orange", "green", "blue"] start 负数 从后数 start 个数(-1开始计数)的位置开始添加
let colors3 = ['red']
let insert3 = colors3.splice(-5, 0, 'yellow', 'brown')
console.log(colors3) // ["yellow", "brown", "red"] start 负数 绝对值大于数组长度,从 0 位开始添加
//替换
let colors = ['red']
let replace = colors.splice(0, 1, 'green', 'blue')
console.log(colors) // ["green", "blue"] 删除 1 项 , 插入 2 项
let colors1 = ['red', 'green', 'blue']
let replace1 = colors1.splice(0, 2, 'orange')
console.log(colors1) // ["orange", "blue"] 删除 2 项,插入 1 项
sort()对数组元素进行排序
用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的。
compareFunction可选 用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的各个字符的Unicode位点进行排序。- firstEl 第一个用于比较的元素。
- secondEl 第二个用于比较的元素。
如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。假设 a 和 b 是两个将要被比较的元素:
- 如果
compareFunction(a, b)小于 0 ,那么 a 会被排列到 b 之前。 - 如果
compareFunction(a, b)等于 0 , a 和 b 的相对位置不变。 - 如果
compareFunction(a, b)大于 0 , b 会被排列到 a 之前。 compareFunction(a, b)必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
//比较字符串函数
function compare(a, b) {
if (a < b) {
return -1
}
if (a > b) {
return 1
}
return 0
}
//比较数字函数
function compareNumbers(a, b) {
return a - b
}
// 没指明比较函数的情况
let num = [1, 5, 37, 80, 9]
console.log(num.sort()) // [1, 37, 5, 80, 9] 按照 Unicode 位点,35 在 5 前面,80 在 9 前面
//有指明比较函数的情况
let num = [1, 5, 37, 80, 9]
console.log(num.sort()) // [1, 37, 5, 80, 9]
console.log(num.sort((a, b) => a - b)) // [1, 5, 9, 37, 80] b-a 降序
reverse()颠倒数组元素的位置
将数组中元素的位置颠倒,并返回该数组。
let arr = ['one', 'two', 'three']
console.log('arr:', arr) // ["one", "two", "three"]
let reversed = arr.reverse()
console.log('reverse:', reversed) // ["three", "two", "one"]
console.log('arr:', arr) // ["three", "two", "one"]
copyWithin()复制数组的一部分到其它位置(ES6)
浅复制数组的一部分到同一数组中的另一个位置,并返回它。
- target 0 为基底的索引,复制序列到该位置。
- 如果是负数,
target将从末尾开始计算。 - 如果
target大于等于arr.length,将会不发生拷贝。 - 如果
target在start之后,复制的序列将被修改以符合arr.length。
- 如果是负数,
- start 0 为基底的索引,开始复制元素的起始位置。
- 如果是负数,
start将从末尾开始计算。 - 如果
start被忽略,copyWithin将会从0开始复制。
- 如果是负数,
- end 0 为基底的索引,开始复制元素的结束位置。
copyWithin将会拷贝到该位置,但不包括end这个位置的元素。- 如果是负数,
end将从末尾开始计算。 - 如果
end被忽略,copyWithin方法将会一直复制至数组结尾(默认为arr.length)。
// target
let arr = ['a', 'b', 'c', 'd', 'e']
console.log(arr.copyWithin(0, 3, 4)) // ["d", "b", "c", "d", "e"] 正常拷贝 不包括 end 元素
let arr2 = ['a', 'b', 'c', 'd', 'e']
console.log(arr2.copyWithin(6, 3, 4)) // ["a", "b", "c", "d", "e"] target 大于 arr.length 不发生拷贝
let arr3 = ['a', 'b', 'c', 'd', 'e']
console.log(arr3.copyWithin(4, 3, 4)) // ["a", "b", "c", "d", "d"] target 大于 start 忽略 start 之前的元素
// start
let arr = ['a', 'b', 'c', 'd', 'e']
console.log(arr.copyWithin(0, -3, 4)) // ["c", "d", "c", "d", "e"] start 从末尾开始计算 -3 也就是 c
let arr2 = ['a', 'b', 'c', 'd', 'e']
console.log(arr2.copyWithin(2)) // ["a", "b", "a", "b", "c"] start 被忽略,copywithin 从 0 开始复制
// end
let arr = ['a', 'b', 'c', 'd', 'e']
console.log(arr.copyWithin(2, 3, 4)) // ["a", "b", "d", "d", "e"] end 不包括这个元素 target c 复制为 d
let arr2 = ['a', 'b', 'c', 'd', 'e']
console.log(arr2.copyWithin(2, 0, -4)) // ["a", "b", "a", "d", "e"] end -4 从末尾开始计算,c 复制为 a
let arr3 = ['a', 'b', 'c', 'd', 'e']
console.log(arr3.copyWithin(2, 3)) // ["a", "b", "d", "e", "e"] end 被忽略,一直复制到结尾 target c 复制 start d 到末尾 e
fill()固定值填充数组(ES6)
- value 用来填充数组元素的值。
start可选 起始索引,默认值为0。end可选 终止索引,默认值为this.length。
let arr = [1, 2, 3, 4, 5]
console.log(arr.fill(6)) // [6, 6, 6, 6, 6]
let arr2 = [1, 2, 3, 4, 5]
console.log(arr2.fill(7, 1, 3)) // [1, 7, 7, 4, 5] 7 填充 1-3 的元素
let arr3 = [1, 2, 3, 4, 5]
console.log(arr3.fill(8, 3)) // [1, 2, 3, 8, 8] 8 填充 大于 3 的元素
let arr4 = [1, 2, 3, 4, 5]
console.log(arr4.fill(9, -4, -1)) // [1, 9, 9, 9, 5] 9 填充 length+start 到 length+end 的元素
let arr5 = [1, 2, 3, 4, 5]
console.log(arr5.fill(8, 3)) // [1, 2, 3, 8, 8] 8 填充 大于 3 的元素
let arr6 = [1, 2, 3, 4, 5]
console.log(arr6.fill(6, 3, 10)) // [1, 2, 3, 6, 6] 6 填充可用部分
访问器方法(不改变原数组)
toString()数组转字符串
返回一个字符串,表示指定的数组及其元素。
let colors = ["red", "blue", "green"]
console.log(colors.toString()) // red,blue,green
toLocaleString()数组转字符串
返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开。
locales可选 带有BCP 47语言标记的字符串或字符串数组,关于locales参数的形式与解释,请看Intl页面。options可选 一个可配置属性的对象,对于数字Number.prototype.toLocaleString(),对于日期Date.prototype.toLocaleString()。
let arr = [1, "a", new Date('21 Dec 1997 9:13:00 UTC')]
const localeString = arr.toLocaleString('en', { timeZone: 'UTC' })
console.log(localeString) // 1,a,12/21/1997, 9:13:00 AM
join()数组转字符串
将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。如果数组只有一个项目,那么将返回该项目而不使用分隔符。
separator可选 指定一个字符串来分隔数组的每个元素。如果需要,将分隔符转换为字符串。如果缺省该值,数组元素用逗号(,)分隔。如果separator是空字符串(""),则所有元素之间都没有任何字符。
let colors = ['red', 'green', undefined, null, 'blue']
console.log(colors.join()) // red,green,,,blue undefined null 转换为空字符串
console.log(colors.join('-')) // red-green---blue
console.log(colors.join('+')) // red+green+++blue
如果一个元素为
undefined或null,它会被转换为空字符串。
concat() 合并数组
用于合并两个或多个数组。
value N可选 数组和/或值,将被合并到一个新的数组中。如果省略了所有valueN参数,则concat会返回调用此方法的现存数组的一个浅拷贝。
let num1 = [[1]]
let num2 = [2, [3]]
let num3 = [5,[6]]
let nums = num1.concat(num2, num3)
console.log(nums) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
//合并嵌套数组
let num1 = [[1]]
let num2 = [2, [3]]
let num3 = [5, [6]]
let nums = num1.concat(num2, num3)
console.log(nums) // [[1],2,[3],5,[6]]
slice()浅拷贝原数组元素
返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。
begin可选 提取起始处的索引(从0开始),从该索引开始提取原数组元素。- 如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,
slice(-2)表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。 - 如果省略
begin,则slice从索引0开始。 - 如果
begin超出原数组的索引范围,则会返回空数组。
- 如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,
end可选 提取终止处的索引(从0开始),在该索引处结束提取原数组元素。slice会提取原数组中索引从begin到end的所有元素(包含begin,但不包含end)。- 如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。
- 如果
end被省略,则slice会一直提取到原数组末尾。 - 如果
end大于数组的长度,slice也会一直提取到原数组末尾。
let fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
let citrus = fruits.slice(1, 3)
console.log(citrus) // ["Orange", "Lemon"]
//类数组对象
function list() {
return Array.prototype.slice.call(arguments)
}
let list1 = list(1, 2, 3)
console.log(list1) // [1, 2, 3]
indexOf()返回指定定元素的第一个索引
返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
- searchElement 要查找的元素。
fromIndex可选 开始查找的位置。- 如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回-1。
- 如果参数中提供的索引值是一个负值,则将其作为数组末尾的一个抵消,即 -1 表示从最后一个元素开始查找,-2表示从倒数第二个元素开始查找 ,以此类推。
- 如果抵消后的索引值仍小于0,则整个数组都将会被查询。
注意:如果参数中提供的索引值是一个负值,并不改变其查找顺序,查找顺序仍然是从前向后查询数组。
let colors = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(colors.indexOf(5)) // 4
console.log(colors.indexOf(5, 10)) // -1 大于等于数组长度,返回 -1
console.log(colors.indexOf(5, -1)) // -1 从倒数第 1 个查找,也就是从 9 向后查找 ,返回 -1
console.log(colors.indexOf(5, -6)) // 4 从倒数第 6 个查找,也就是从 4 向后查找,返回 4
console.log(colors.indexOf(5, -10)) // 4 抵消后索引值小于 0 ,查找整个数组,返回 4
lastIndexOf()返回指定元素的最后一个索引
返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。
- searchElement 被查找的元素。
fromIndex可选 从此位置开始逆向查找。默认为数组的长度减 1(arr.length - 1),即整个数组都被查找。- 如果该值大于或等于数组的长度,则整个数组会被查找。
- 如果为负值,将其视为从数组末尾向前的偏移。即使该值为负,数组仍然会被从后向前查找。
- 如果为负值,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。
let colors = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(colors.lastIndexOf(1)) // 0 默认情况,整个数组都被查找
console.log(colors.lastIndexOf(9, 9)) // 8 fromIndex 大于等于数组长度,整个数组都被查找
console.log(colors.lastIndexOf(5, -5)) // 4 fromIndex 为负值,从数组末尾向前的偏移,这里就是从 5 开始查找,所以能找到
console.log(colors.lastIndexOf(5, -6)) // -1 这里从 4 开始查找,因为从后向前查找,所以返回 -1
console.log(colors.lastIndexOf(5, -10)) // -1 fromIndex 绝对值大于数组长度,则方法返回 -1
includes()数组是否包含指定值(ES7)
用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
- valueToFind 需要查找的元素值。
fromIndex可选 从fromIndex索引处开始查找valueToFind。- 如果为负值,则按升序从
array.length + fromIndex的索引开始搜。
- 如果为负值,则按升序从
Note: 使用
includes()比较字符串和字符时是区分大小写。
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(numbers.includes(5)) // true
console.log(numbers.includes(5, 6)) // false fromIndex 大于 valueToFind 索引值
console.log(numbers.includes(5, 10)) // false fromIndex 大于等于数组长度
console.log(numbers.includes(5, -5)) // true array.length + fromIndex 也就是从索引值 4 开始查找
console.log(numbers.includes(8, -1)) // false 从索引值 8 开始查找
console.log(numbers.includes(5, -10)) // true 如果计算出的索引小于 0,则整个数组都会被搜索。
迭代方法
forEach()对数组的每个元素执行一次给定的函数
按升序为数组中含有效值的每一项执行一次 callback 函数,那些已删除(使用delete方法等情况)或者未初始化的项将被跳过(例如在稀疏数组上,不包括undefined)。
- callback 为数组中每个元素执行的函数,该函数接收一至三个参数:
- currentValue 数组中正在处理的当前元素。
index可选 数组中正在处理的当前元素的索引。array可选forEach()方法正在操作的数组。
thisArg可选 当执行回调函数callback时,用作this的值。- 如果
thisArg参数有值,则每次callback函数被调用时,this都会指向thisArg参数。 - 如果省略了
thisArg参数,或者其值为null或undefined,this则指向全局对象。
- 如果
注意:
forEach()遍历的范围在第一次调用callback前就会确定。调用
forEach后添加到数组中的项不会被callback访问到。如果已经存在的值被改变,则传递给
callback的值是forEach()遍历到他们那一刻的值。如果已访问的元素在迭代时被删除了(例如使用
shift()),之后元素将被跳过。
forEach()为每个数组元素执行一次callback函数;它总是返回undefined值(也就是没有返回值),并且不可链式调用。
forEach()被调用时,不会直接改变调用它的对象,但是那个对象可能会被callback函数改变。
- 值类型不会被改变,引用类型会被改变。
除了抛出异常以外,没有办法中止或跳出
forEach()循环。
//不对未初始化的值进行任何操作(稀疏数组)
let nums = [1, 3, , 7]
let numCallbackRuns = 0
nums.forEach(function (element) {
console.log(element)
numCallbackRuns++
})
console.log('numCallbackRuns:', numCallbackRuns) // 1 3 7 numCallbackRuns: 3
//使用thisArgs
function Counter() {
this.sum = 0
this.count = 0
}
Counter.prototype.add = function (array) {
array.forEach(function (entry) {
this.sum += entry
++this.count
}, this)
//因为 thisArg 参数(this)传给了 forEach(),每次调用时,它都被传给 callback 函数,作为它的 this 值。
}
const obj = new Counter()
obj.add([2, 5, 9])
// 3 === (1 + 1 + 1)
obj.sum
// 16 === (2 + 5 + 9)
//使用箭头函数表达式传入函数,thisArgs 参数会被忽略
let nums2 = [1, 2, 3]
nums2.forEach((v, i, arr) => {
console.log(this) // window window window
})
//如果数组在迭代时被修改了,则其他元素会被跳过
let words = ['one', 'two', 'three', 'four']
words.forEach((word) => {
console.log(word)
if (word === 'two') {
words.shift()
}
}) // one two four
//没有返回值
let nums3 = [1, 2, 3, 4, 5]
let value = nums3.forEach((v, i, arr) => { })
console.log(value) // undefined
//不支持链式调用
[1, 2, 3, 4, 5].forEach(item => {
console.log(item)
}).filter(item => {
return item > 2 // Uncaught TypeError: Cannot read property 'filter' of undefined
})
//forEach() 被调用时,调用它的对象被 callback 函数改变
let nums4 = [1, 2, 3, 4, 5]
nums4.forEach((v, i, arr) => {
arr[i] = v * 2
})
console.log(nums4) // [2, 4, 6, 8, 10] 改变
nums4.forEach(item => {
item = item * 2
})
console.log(nums4) // [2, 4, 6, 8, 10] 没有改变
//除了抛出异常,没办法中止或跳出 forEach() 循环
let nums5 = [1, 2, 3, 4, 5]
// nums5.forEach((v, i, arr) => {
// console.log(v)
// if (i === 2) {
// break // Uncaught SyntaxError: Illegal break statement
// }
// })
nums5.forEach((v, i, arr) => {
console.log(v)
if (v === 2) {
console.log(666)
return false // 1 2 666 3 4 5
}
})
map()对数组每一项都执行传入的函数,返回新数组
给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。
callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。
- callback 生成新数组元素的函数,使用三个参数:
- currentValue
callback数组中正在处理的当前元素。 index可选callback数组中正在处理的当前元素的索引。array可选map方法调用的数组。
- currentValue
thisArg可选 执行callback函数时值被用作this。
map生成新数组,当你不打算使用返回的新数组却使用map是违背设计初衷的,请使用forEach或者for-of替代。你不该使用
map的情况:
- 你不打算使用返回的新数组;
- 你没有从回调函数中返回值。
如果
thisArg参数提供给map,则会被用作回调函数的this值。否则undefined会被用作回调函数的this值。
map不修改调用它的原数组本身(当然可以在callback执行时改变原数组)。
map方法处理数组元素的范围是在callback方法第一次调用之前就确定了。调用
map方法之后追加的数组元素不会被callback访问。如果存在的数组元素改变了,那么传给
callback的值是map访问该元素时的值。在
map函数调用后但在访问该元素前,该元素被删除的话,则无法被访问到。根据规范中定义的算法,如果被
map调用的数组是离散的,新数组将也是离散的保持相同的索引为空。
//map 返回新数组 原数组不变(可以通过 callback 改变)
let nums = [1, 4, 9]
let roots = nums.map(Math.sqrt)
console.log(roots, nums) // [1, 2, 3] [1, 4, 9]
//返回值是 undefined 也会组合成新数组
let newArr = [1, 2, 3, 4, 5].map(item => {
if (item > 3) {
return item
}
})
console.log(newArr) // [undefined, undefined, undefined, 4, 5]
//使用 map 重新格式化数组中的对象
let kvArray = [{ key: 1, value: 10 }, { key: 2, value: 20 }, { key: 3, value: 30 }]
let refmArray = kvArray.map(function (obj) {
let rObj = {}
rObj[obj.key] = obj.value
return rObj
})
console.log(refmArray, kvArray) // [{1:10},{2:20},{3:30}] [{ key: 1, value: 10 }, { key: 2, value: 20 }, { key: 3, value: 30 }]
//使用一个包含一个参数的函数来mapping(构建)一个数字数组
let nums2 = [1, 4, 9]
let doubles = nums2.map(function (num) {
return num * 2
})
console.log(doubles, nums2) // [2, 8, 18] [1, 4, 9]
//querySelectorAll 应用
let elems = document.querySelectorAll('select option:checked')
let values = Array.prototype.map.call(elems, function (obj) {
return obj.value
})
console.log(values) // [] 我们获得了文档里所有选中的选项,并将其打印
技巧案例
console.log(['1', '2', '3'].map(parseInt)) // [1, NaN, NaN]
出现这个结果是因为parseInt接收两个参数:
- 第一个参数是一个表达式,表示要被解析的值。
- 第二个参数是一个数字,表示字符串的基数。
而map的第三个参数原数组本身被parseInt忽视,第二个参数传过来的索引值被当成进制数来使用,所以返回NaN。
解决方案
//返回10进制整数
function returnInt(element) {
return parseInt(element, 10)
}
console.log(['1', '2', '3'].map(returnInt)) // [1, 2, 3]
//使用箭头函数
console.log(['1', '2', '3'].map(str => parseInt(str))) // [1, 2, 3]
//使用Number转换字符串
console.log(['1', '2', '3'].map(Number)) // [1, 2, 3]
filter()过滤原始函数,返回新数组
为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。
- callback 用来测试数组的每个元素的函数。返回
true表示该元素通过测试,保留该元素,false则不保留。它接受以下三个参数:- element 数组中当前正在处理的元素。
index可选 正在处理的元素在数组中的索引。array可选 调用了filter的数组本身。
thisArg可选 执行callback时,用于this的值。
callback只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过
callback测试的元素会被跳过,不会被包含在新数组中。如果为
filter提供一个thisArg参数,则它会被作为callback被调用时的this值。否则,
callback的this值在非严格模式下将是全局对象,严格模式下为undefined。
filter不会改变原数组,它返回过滤后的新数组。
filter遍历的元素范围在第一次调用callback之前就已经确定了。在调用
filter之后被添加到数组中的元素不会被filter遍历到。如果已经存在的元素被改变了,则他们传入
callback的值是filter遍历到它们那一刻的值。被删除或从来未被赋值的元素不会被遍历到。
const words = ['HTML', 'CSS', 'JavaScript', 'Java', 'Vue', 'React']
const result = words.filter(word => word.length > 6)
console.log(result) // ["JavaScript"]
some()数组中是否有满足条件的元素
数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。
如果找到了这样一个值,some() 将会立即返回 true。否则,some() 返回 false。
callback 只会在那些“有值”的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。
- callback 用来测试每个元素的函数,接受三个参数:
- element 数组中正在处理的元素。
index可选 数组中正在处理的元素的索引值。array可选some()被调用的数组。
thisArg可选 执行callback时使用的this值。
如果一个
thisArg参数提供给some(),它将被用作调用的callback的this值。否则, 它的thisvalue 将是undefined。
some()被调用时不会改变数组。
some()遍历的元素的范围在第一次调用callback前就已经确定了。在调用
some()后被添加到数组中的值不会被callback访问到。如果数组中存在且还未被访问到的元素被
callback改变了,则其传递给callback的值是some()访问到它那一刻的值。已经被删除的元素不会被访问到。
//测试数组元素的值
function isBiggerThan10(element, index, array) {
return element > 10
}
console.log([2, 5, 8, 9, 1].some(isBiggerThan10)) // false
console.log([12, 5, 8, 9, 1].some(isBiggerThan10)) // true
//使用箭头函数测试数组元素的值
console.log([1, 5, 6, 9].some(x => x > 10)) // false
console.log([12, 5, 1, 9].some(x => x > 10)) // true
//判断数组元素中是否存在某个值
let fruits = ['apple', 'banana', 'mango', 'guava']
function checkAvailability(arr, val) {
return arr.some(function (arrVal) {
return val === arrVal
})
}
console.log(checkAvailability(fruits, 'kela')) // false
console.log(checkAvailability(fruits, 'banana')) // true
//将任意值转换为布尔类型
let TRUTHY_VALUES = [true, 'true', 1]
function getBoolean(value) {
'use strict'
if (typeof value === 'string') {
value = value.toLowerCase().trim()
}
return TRUTHY_VALUES.some(function (t) {
return t === value
})
}
console.log(getBoolean(false)) // false
console.log(getBoolean('false')) // false
console.log(getBoolean(1)) // true
console.log(getBoolean('true')) // true
every()数组中所有元素是否满足条件
为数组中的每个元素执行一次 callback 函数,直到它找到一个会使 callback 返回 falsy 的元素。
如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 true,every 就会返回 true。
callback 只会为那些已经被赋值的索引调用。不会为那些被删除或从未被赋值的索引调用。
- callback 用来测试每个元素的函数,它可以接收三个参数:
- element 用于测试的当前值。
index可选 用于测试的当前值的索引。array可选 调用every的当前数组。
- thisArg 执行
callback时使用的this值。
如果为
every提供一个thisArg参数,则该参数为调用callback时的this值。如果省略该参数,则
callback被调用时的this值,在非严格模式下为全局对象,在严格模式下传入undefined。
every不会改变原数组。
every遍历的元素范围在第一次调用callback之前就已确定了。在调用
every之后添加到数组中的元素不会被callback访问到。如果数组中存在的元素被更改,则他们传入
callback的值是every访问到他们那一刻的值。那些被删除的元素或从来未被赋值的元素将不会被访问到。
every和数学中的"所有"类似,当所有的元素都符合条件才会返回true。正因如此,若传入一个空数组,无论如何都会返回true。
//检测所有数组元素的大小
function isBigEnough(element, index, array) {
return element >= 10
}
console.log([12, 5, 8, 130, 44].every(isBigEnough)) // false
console.log([12, 54, 18, 130, 44].every(isBigEnough)) // true
//箭头函数
console.log([12, 5, 8, 130, 44].every(x => x >= 10)) // false
console.log([12, 54, 18, 130, 44].every(x => x >= 10)) // true
reduce()为数组提供一个累加器,汇总为一个值
为数组中的每一个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素。
-
callback 执行数组中每个值 (如果没有提供
initialValue则第一个值除外)的函数,包含四个参数:accumulator累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。currentValue数组中正在处理的元素。index可选 数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。array可选 调用reduce()的数组。
-
initialValue可选 作为第一次调用callback函数时的第一个参数的值。如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
回调函数第一次执行时,
accumulator和currentValue的取值有两种情况:如果调用
reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;如果没有提供
initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。如果数组为空且没有提供
initialValue,会抛出TypeError。如果数组仅有一个元素(无论位置如何)并且没有提供
initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。
注意: 如果没有提供
initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
提供初始值通常更安全,正如下面的例子,如果没有提供initialValue,则可能有四种输出:
let maxCallback = (acc, cur) => Math.max(acc.x, cur.x)
let maxCallback2 = (max, cur) => Math.max(max, cur)
// reduce()没有初始值
console.log([{ x: 2 }, { x: 22 }, { x: 42 }].reduce(maxCallback)) // NaN
console.log([{ x: 2 }, { x: 22 }].reduce(maxCallback)) // 22 没提供 initialValue,accumulator 取 {x:2},currentValue 取数组中的第二个值 {x:22}
console.log([{ x: 2 }].reduce(maxCallback)) // {x: 2} 数组只用一个元素,此唯一值将被返回并且 callback 不会被执行
console.log([].reduce(maxCallback)) //Uncaught TypeError: Reduce of empty array with no initial value 数组为空且没有提供 initialValue
// map/reduce 这是更好的方案,既是传入空数组或更大数组也可正常执行
console.log([{ x: 22 }, { x: 42 }].map(el => el.x).reduce(maxCallback2, -Infinity)) // 42
第一个为什么输出 NaN 呢?
没提供
initialValue,accumulator取{x:2},currentValue取数组中的第二个值{x:22}。就相当于
[{ x: 22 }, { x: 42 }].reduce(maxCallback, { x: 2 })。第一次运算是
{ x:2 }和{ x:22 }结果是 22。第二次运算是 22 和
{ x:42 },(22).x 是undefined,那么Math.max(undefined,42)结果是NaN。所以先试用 map 把 x 都取出来是更好的方案。
reduce() 如何运行
假如运行下段reduce()代码:
[0, 1, 2, 3, 4].reduce(function (accumulator, currentValue, currentIndex, array) {
return accumulator + currentValue
})
//使用箭头函数
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr)
callback 被调用四次,每次调用的参数和返回值如下表:
callback | accumulator | currentValue | currentIndex | array | return value |
|---|---|---|---|---|---|
| first call | 0 | 1 | 1 | [0, 1, 2, 3, 4] | 1 |
| second call | 1 | 2 | 2 | [0, 1, 2, 3, 4] | 3 |
| third call | 3 | 3 | 3 | [0, 1, 2, 3, 4] | 6 |
| fourth call | 6 | 4 | 4 | [0, 1, 2, 3, 4] | 10 |
由reduce返回的值将是最后一次回调返回值(10)。
如果你打算提供一个初始值作为reduce()方法的第二个参数,以下是运行过程及结果:
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue
}, 10)
callback | accumulator | currentValue | currentIndex | array | return value |
|---|---|---|---|---|---|
| first call | 10 | 0 | 0 | [0, 1, 2, 3, 4] | 10 |
| second call | 10 | 1 | 1 | [0, 1, 2, 3, 4] | 11 |
| third call | 11 | 2 | 2 | [0, 1, 2, 3, 4] | 13 |
| fourth call | 13 | 3 | 3 | [0, 1, 2, 3, 4] | 16 |
| fifth call | 16 | 4 | 4 | [0, 1, 2, 3, 4] | 20 |
这种情况下reduce()返回的值是20。
//数组里所有值的和
let sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
return accumulator + currentValue
}, 0)
console.log(sum) // 6
//将二维数组转化为一维
let flattened = [[0, 1], [2, 3], [4, 5]].reduce(
function (a, b) {
return a.concat(b)
}, []
)
console.log(flattened) // [0, 1, 2, 3, 4, 5]
//计算数组中每个元素出现的次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']
let countedNames = names.reduce(function (allNames, name) {
if (name in allNames) {
allNames[name]++
} else {
allNames[name] = 1
}
return allNames
}, {})
console.log(countedNames) // {Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
//按属性对object分类
var people = [
{ name: 'Alice', age: 21 },
{ name: 'Max', age: 20 },
{ name: 'Jane', age: 20 }
]
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
let key = obj[property]
if (!acc[key]) {
acc[key] = []
}
acc[key].push(obj)
return acc
}, {})
}
let groupedPeople = groupBy(people, 'age')
console.log(groupedPeople)
// {
// 20: [
// { name: 'Max', age: 20 },
// { name: 'Jane', age: 20 }
// ],
// 21: [{ name: 'Alice', age: 21 }]
// }
reduceRight()为数组提供一个累加器,将其减少为单个值(从右到左)
为数组中每个元素调用一次 callback 回调函数,但是数组中被删除的索引或从未被赋值的索引会跳过。
-
callback 一个回调函数,用于操作数组中的每个元素,它可接受四个参数:
-
accumulator 累加器:上一次调用回调函数时,回调函数返回的值。
首次调用回调函数时,如果
initialValue存在,累加器即为initialValue,否则须为数组中的最后一个元素。 -
currentValue 当前元素:当前被处理的元素。
-
index可选 数组中当前被处理的元素的索引。 -
array可选 调用reduceRight()的数组。
-
-
initialValue可选 首次调用callback函数时,累加器accumulator的值。如果未提供该初始值,则将使用数组中的最后一个元素,并跳过该元素。
如果不给出初始值,则需保证数组不为空。 否则,在空数组上调用
reduce或reduceRight且未提供初始值(例如[].reduce( (acc, cur, idx, arr) => {} ))的话,会导致类型错误TypeError: reduce of empty array with no initial value。
可以像下面这样调用
reduceRight的回调函数callback:array.reduceRight(function (accumulator, currentValue, index, array) { // ... })首次调用回调函数时,
accumulator和currentValue的可能取值情况有两种:
- 如果在调用
reduceRight时提供了initialValue参数,则accumulator等于initialValue,currentValue等于数组中的最后一个元素。- 如果没有提供
initialValue参数,则accumulator等于数组最后一个元素,currentValue等于数组中倒数第二个元素。如果数组为空,但提供了
initialValue参数,或如果数组中只有一个元素,且没有提供initialValue参数,将会直接返回initialValue参数或数组中的那一个元素。这两种情况下,都不会调用callback函数。
最终,首次调用时的情况可汇总为此表:
| 数组内元素数量 | 是否提供 initialValue | 结果 |
|---|---|---|
| > 1 | 未提供 | accumulator 为数组中(下略)最后一个元素 currentValue 为倒数第二个元素 |
| 提供 | accumulator 为 initialValue currentValue 为最后一个元素 | |
| = 1 | 未提供 | 直接返回数组中的唯一一个元素 |
| = 0 | 提供 | 直接返回 initialValue |
| 未提供 | 抛出 TypeError 错误 |
该函数的完整执行过程见下例:
[0, 1, 2, 3, 4].reduceRight(function (previousValue, currentValue, index, array) {
return previousValue + currentValue
})
一共会调用四次回调函数,每次调用的参数及返回值如下:
callback | previousValue | currentValue | index | array | 返回值 |
|---|---|---|---|---|---|
| 第一次调用 | 4 | 3 | 3 | [0,1,2,3,4] | 7 |
| 第二次调用 | 7 | 2 | 2 | [0,1,2,3,4] | 9 |
| 第三次调用 | 9 | 1 | 1 | [0,1,2,3,4] | 10 |
| 第四次调用 | 10 | 0 | 0 | [0,1,2,3,4] | 10 |
reduceRight 返回值是最后一次调用回调的返回值(10)。
如果提供了一个 initialValue 参数,则结果如下:
[0, 1, 2, 3, 4].reduceRight(function (previousValue, currentValue, index, array) {
return previousValue + currentValue
}, 10)
callback | previousValue | currentValue | index | array | 返回值 |
|---|---|---|---|---|---|
| 第一次调用 | 10 | 4 | 4 | [0,1,2,3,4] | 14 |
| 第二次调用 | 14 | 3 | 3 | [0,1,2,3,4] | 17 |
| 第三次调用 | 17 | 2 | 2 | [0,1,2,3,4] | 19 |
| 第四次调用 | 19 | 1 | 1 | [0,1,2,3,4] | 20 |
| 第五次调用 | 20 | 0 | 0 | [0,1,2,3,4] | 20 |
这时,reduceRight 返回值为 20。
//求一个数组中所有值的和
let sum = [0, 1, 2, 3].reduceRight(function (a, b) {
return a + b
})
console.log(sum) // 6
//扁平化(flatten)一个二维数组
let flattened = [[0, 1], [2, 3], [4, 5]].reduceRight(function (a, b) {
return a.concat(b)
}, [])
console.log(flattened) // [4, 5, 2, 3, 0, 1]
//展示 reduce 与 reduceRight 之间的区别
let a = ['1', '2', '3', '4', '5']
let left = a.reduce(function (prev, cur) {
return prev + cur
})
let right = a.reduceRight(function (prev, cur) {
return prev + cur
})
console.log(left) // 12345
console.log(right) // 54321
find()&findIndex()(ES6)
find方法对数组中的每一项元素执行一次 callback 函数,直至有一个 callback 返回 true。
当找到了这样一个元素后,该方法会立即返回这个元素的值,否则返回 undefined。
注意:callback 函数会为数组中的每个索引调用即从 0 到 length - 1,而不仅仅是那些被赋值的索引,这意味着对于稀疏数组来说,该方法的效率要低于那些只遍历有值的索引的方法。
- callback 在数组每一项上执行的函数,接收 3 个参数:
- element 当前遍历到的元素。
index可选 当前遍历到的索引。array可选 数组本身。
thisArg可选 执行回调时用作this的对象。
如果提供了
thisArg参数,那么它将作为每次callback函数执行时的this,如果未提供,则使用undefined。
find方法不会改变数组。在第一次调用
callback函数时会确定元素的索引范围,因此在find方法开始执行之后添加到数组的新元素将不会被callback函数访问到。如果数组中一个尚未被
callback函数访问到的元素的值被callback函数所改变,那么当callback函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素仍旧会被访问到,但是其值已经是 undefined 了。
//用对象的属性查找数组里的对象
let inventory = [
{ name: 'apples', quantity: 2 },
{ name: 'bananas', quantity: 0 },
{ name: 'cherries', quantity: 5 }
]
function findCherries(fruit) {
return fruit.name === 'cherries'
}
console.log(inventory.find(findCherries)) // {name: "cherries", quantity: 5}
//寻找数组中的质数
function isPrime(element, index, array) {
let start = 2
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) {
return false
}
}
return element > 1
}
console.log([4, 6, 8, 12].find(isPrime)) // undefined 找不到质数返回 false
console.log([4, 5, 8, 12].find(isPrime)) // 5
findIndex方法对数组中的每个数组索引0..length-1(包括)执行一次callback函数,直到找到一个callback函数返回真实值(强制为true)的值。
如果找到这样的元素,findIndex会立即返回该元素的索引。如果回调从不返回真值,或者数组的length为0,则findIndex返回-1。
与某些其他数组方法(如Array#some)不同,在稀疏数组中,即使对于数组中不存在的条目的索引也会调用回调函数。
- callback 针对数组中的每个元素, 都会执行该回调函数, 执行时会自动传入下面三个参数:
- element 当前元素。
- index 当前元素的索引。
- array 调用
findIndex的数组。
- thisArg 可选。执行
callback时作为this对象的值。
如果一个
thisArg参数被提供给findIndex, 它将会被当作this使用在每次回调函数被调用的时候。如果没有被提供,将会使用undefined。
findIndex不会修改所调用的数组。在第一次调用
callback函数时会确定元素的索引范围,因此在findIndex方法开始执行之后添加到数组的新元素将不会被callback函数访问到。如果数组中一个尚未被
callback函数访问到的元素的值被callback函数所改变,那么当callback函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素仍然会被访问到。
//查找数组中首个质数元素的索引
function isPrime(element, index, array) {
let start = 2
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) {
return false
}
}
return element > 1
}
console.log([4, 6, 8, 12].findIndex(isPrime)) // -1
console.log([4, 6, 7, 12].findIndex(isPrime)) // 2
keys()&values()&entries()(ES6)
keys() 方法返回一个包含数组中每个索引键的Array Iterator对象。
const arr = ['a', 'b', 'c']
const iterator = arr.keys()
for (const key of iterator) {
console.log(key)
}
// 0
// 1
// 2
let arr2 = ['a', 'c']
let sparseKeys = Object.keys(arr)
let denseKeys = [...arr.keys()]
console.log(sparseKeys) // ["0", "1", "2"]
console.log(denseKeys) // [0, 1, 2] 索引迭代器会包含那些没有对应元素的索引
values() 方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值。
const arr = ['a', 'b', 'c']
const iterator = arr.values()
for (const value of iterator) {
console.log(value)
}
// a
// b
// c
//使用 for...of 循环进行迭代
let arr2 = ['w', 'y', 'k', 'o', 'p']
let eArr = arr2.values()
for (let letter of eArr) {
console.log(letter)
}
//w
//y
//k
//o
//p
//使用 .next() 迭代
let arr4 = ['a', 'b', 'c', 'd', 'e']
let iterator = arr4.values()
console.log(iterator.next()) // {value: "a", done: false}
console.log(iterator.next().value) // b
console.log(iterator.next()['value']) // c
console.log(iterator.next()) // {value: "d", done: false}
console.log(iterator.next()) // {value: "e", done: false}
console.log(iterator.next()) // {value: undefined, done: true}
console.log(iterator.next().value) // undefined
//如果数组中元素改变,那么迭代器的值也会改变
let arr5 = ['a', 'b', 'c', 'd', 'e']
let iterator = arr5.values()
console.log(iterator) // Array Iterator { }
iterator.next().value // "a"
arr5[1] = 'n'
iterator.next().value // "n"
entries() 方法返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键/值对。
// Array Iterator
let arr = ['a', 'b', 'c']
let iterator = arr.entries()
console.log(iterator) // Array Iterator {}
// iterator.next()
console.log(iterator.next()) // {value: [0, "a"], done: false}
// iterator.next方法运行
let a = []
for (let i = 0; i < arr.length; i++) {
let tem = iterator.next() // 每次迭代时更新next
console.log(tem.done) // 这里可以看到更新后的done都是false
if (tem.done !== true) { // 遍历迭代器结束done才是true
console.log(tem.value)
a[i] = tem.value
}
}
// false
// [1, "b"]
// false
// [2, "c"]
// true
console.log(a) // [[1, "b"],[2, "c"]]