数组是前端工程师们最常用到的数据集合之一,掌握好了数组使用犹如获得神兵利器, 方便我们处理得到想要的数据和结构,提高工(shao)作(jia)效(dian)率(ban)不说, 磕出来的代码也能整洁一些。
数组的方法
- from 把类数组或可迭代对象变成数组
- of 创建一个具有可变数量参数的数组
- isArray 判断是否是数组
- concat 合并两个或多个数组并返回新的数组
- copywithin 浅拷贝数组的一部分到数组中的另一个位置并返回 改变原数组
- every 判断数组内的所有元素是否都符合条件,返回Boolean
- some 判断数组中是不是至少有1个元素符合条件,返回Boolean
- forEach 遍历数组
- map 遍历数组并返回数组对象
- fill 用固定值填充数组中某段位置内的元素。
- filter 过滤数组
- find 返回数组中满足条件的第一个元素的值
- findIndex 返回数组中满足条件的第一个元素的索引
- includes 判断一个数组是否包含指定的值
- indexOf 返回数组中满足条件的第一个元素的索引
- lastIndexOf 返回在数组中满足条件的最后一个元素的索引
- flat 返回扁平化数组
- flatMap 返回扁平化数组
- join 用指定的分隔符将数组每一项拼接成字符串
- pop 从数组中删除最后一个元素,并返回该元素的值 改变原数组
- push 从数组中添加最后一个元素,并返回数组length 改变原数组
- unshift 将一个或多个元素添加到数组的开头 改变原数组
- shift 删除第一个元素,并返回该元素的值 改变原数组
- slice 返回指定范围内的数据组成的数组
- sort 对数组进行排序并返回 改变原数组
- splice 通过删除或替换现有元素或者原地添加新的元素来修改数组,返回被修改的内容 改变原数组
- reduce 遍历数组,将其结果汇总为单个返回值
- reduceRight 从右往左遍历数组,将其结果汇总为单个返回值
- toString 返回一个字符串,表示指定的数组及其元素
- toLocaleString 返回一个字符串表示数组中的元素
- entries 返回包含数组中每个索引的键/值对的Array Iterator对象
- values 返回包含数组每个索引的值的Array Iterator对象
- keys 返回包含数组中每个索引键的Array Iterator对象。
数组的方法详解
from && of
let arr = Array.from(arrayLike[, mapFn[, thisArg]])
参数
- arrayLike 伪数组对象或可迭代对象
- mapFn[可选] 如果指定了该参数,新数组中的每个元素会执行该回调函数
- thisArg[可选] 回调函数this对象
let arr = Array.of(element0[, element1[, ...[, elementN]]])
参数
- elementN 任意个参数,将按顺序成为返回数组中的元素。
兼容性
- IE不支持
特点
- 返回浅拷贝的数组
用例
Array.from('foo'); // output [ "f", "o", "o" ] 相当于'foo'.split('')
Array.from(new Set(['foo', 'bar', 'baz', 'foo'])); // output [ "foo", "bar", "baz" ]
Array.from([1, 2, 3], x => x + x); // output [2, 4, 6]
Array.of(1); // output [1]
Array.of(1, 2, 3); // output [1, 2, 3]
Array.of(undefined); // output [undefined]
isArray
let value = Array.isArray(obj)
参数
- obj 需要检测的值。
兼容性
- IE不支持
特点
- 如果值是 Array,则返回true; 否则返回false
用例
Array.isArray([]); // output true
Array.isArray(new Array()); // output true
concat
let array = arr.concat(value1[, value2[, ...[, valueN]]])
参数
- valueN[可选] 数组和/或值,将被合并到一个新的数组中
特点
- 返回浅拷贝数组
用例
var arr1 = ['a', 'b', 'c'];
var arr2 = [1, 2, 3];
arr1.concat(arr2); // output ['a', 'b', 'c', 1, 2, 3]
every && some && forEach && map
let value1 = arr.every(callback(element[, index[, array]])[, thisArg]) | arr.some(callback(element[, index[, array]])[, thisArg])
参数
- callback函数
- element 当前值
- index[可选] 当前值的索引
- array[可选] 当前数组
- thisArg[可选] 执行callback 时使用的 this 值
兼容性
- IE9+
特点
- 返回一个布尔值(由此可以使用return来中断遍历,every返回false,some返回true)
- 当为空数组,every()返回true,some()返回false
- 在调用方法之后添加到数组中的元素不会被回调函数访问到
用例
[12, 5, 8, 130, 44].every((element, index, array)=> element >= 10)
// output false
[12, 5, 8, 130, 44].some((element, index, array)=> element >= 10)
// output true
arr.forEach(callback(currentValue [, index [, array]])[, thisArg])
参数
- callback函数
- element 当前值
- index[可选] 当前值的索引
- array[可选] 当前数组
- thisArg[可选] 执行callback 时使用的this值
兼容性
- IE9+
特点
- 函数返回值为undefined
- 除了抛出异常以外,没有办法中止或跳出 forEach() 循环
- 调用 forEach 后添加到数组中的项不会被 callback 访问到
- 如果已经存在的值被改变,则传递给 callback 的值是 forEach() 遍历到他们那一刻的值
- 如果已访问的元素在迭代时被删除了(例如使用 shift()),之后的元素将被跳过
- 使用箭头函数表达式来传入函数参数, thisArg 参数会被忽略,因为箭头函数在词法上绑定了 this 值
用例
[1,2,3,4].forEach(function(element){
console.log(element);
});
// 如果数组在迭代时被修改了,则其他元素会被跳过。
var words = ['one', 'two', 'three', 'four'];
words.forEach(function(word) {
console.log(word);
if (word === 'two') {
words.shift();
}
});
// one
// two
// four
var array = arr.map(function callback(currentValue[, index[, array]]) {
return element
}[, thisArg])
参数
- callback函数
- element 当前值
- index[可选] 当前值的索引
- array[可选] 当前数组
- thisArg[可选] 执行callback 时使用的this值
兼容性
- IE9+
特点
- 回调函数需要有返回值
- 调用map方法之后追加的数组元素不会被callback访问
用例
var doubles = [1, 4, 9].map(function(num) {
return num * 2;
});
find && findIndex
let value = arr.find(callback[, thisArg])
let index = arr.findIndex(callback[, thisArg])
参数
- callback函数
- element 当前值
- index[可选] 当前值的索引
- array[可选] 当前数组
- thisArg[可选] 执行callback 时使用的 this 值
兼容性
- IE不支持
特点
- 返回第一个满足条件的值,否则find()返回 undefined,findIndex()返回-1。(由此可以使用return true来中断遍历)
- 被删除的元素仍旧会被访问到,但是其值已经是undefined了。
用例
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
console.log(inventory.find(fruit=> {
return fruit.name === 'cherries';
}));
// output { name: 'cherries', quantity: 5 }
console.log(inventory.findIndex(fruit=> {
return fruit.name === 'cherries';
}));
// output 2
includes && indexOf && lastIndexOf
let value = arr.includes(valueToFind[, fromIndex])
let index = arr.indexOf(valueToFind[, fromIndex]) | arr.lastIndexOf(valueToFind[, fromIndex])
参数
- valueToFind 需要查找的元素值 比较字符串和字符时是区分大小写
- fromIndex
| includes,indexOf | lastIndexOf | | 默认值 | 0 | arr.length - 1 | | 为负值 | 升序从末尾向前的偏移查找 | 逆序从末尾向前的偏移查找 | | fromIndex大于等于数组的长度 | 返回 false/-1(数组不会被搜索) | 则整个数组都会被搜索 | | 计算出的索引小于 0 | 则整个数组都会被搜索 | 返回-1(数组不会被搜索) |
兼容性
- includes() IE不支持
- indexOf(),lastIndexOf() IE9+
特点
- includes()返回一个布尔值
- indexOf(),lastIndexOf()返回查找到的元素的索引值,如果不存在则返回-1
- includes(),indexOf(),lastIndexOf()使用严格相等比较
用例
const arr = [1, 2, 3]
arr.includes(2) // output true
arr.includes(3, 3); // output false
arr.includes(3, -1); // output true
arr.indexOf(7); // output -1
arr.indexOf(3, 2); // output 2
arr.indexOf(2, -1); // output -1
arr.lastIndexOf(1) // output 0
arr.lastIndexOf(1,9) // output 0
arr.lastIndexOf(1,-9) // output -1
扩展
includes不要求this值是数组对象,所以它可以被用于其他类型的对象 (比如类数组对象);
(function() {
console.log([].includes.call(arguments, 'a')); // output true
console.log([].includes.call(arguments, 'd')); // output false
})('a','b','c');
fill
var array = arr.fill(value[, start[, end]])
参数
- value 用来填充数组元素的值
- start[可选] 起始索引,默认值为0
- end[可选] 终止索引,默认值为 this.length。
兼容性
- IE不支持
特点
- 返回修改后的数组
- start可为负数, 负数时计算成为length+start,end可为负数, 负数时计算成为 length+end。
- 会改变原函数
用例
[1, 2, 3].fill(4); // output [4, 4, 4]
[1, 2, 3].fill(4, 1, 2); // output [1, 4, 3]
扩展
fill 方法故意被设计成通用方法, 该方法不要求 this 是数组对象
[].fill.call({ length: 3 }, 4); // output {0: 4, 1: 4, 2: 4, length: 3}
filter
var array = arr.filter(callback(element[, index[, array]])[, thisArg])
参数
- callback函数
- element 当前值
- index[可选] 当前值的索引
- array[可选] 当前数组
- thisArg[可选] 执行callback 时使用的 this 值
兼容性
- IE9+
特点
- 没有满足条件的数据则返回空数组。
- 在调用 filter 之后被添加到数组中的元素不会被 filter 遍历到。
- 如果已经存在的元素被改变了,则他们传入 callback 的值是 filter 遍历到它们那一刻的值。
用例
var filtered = [12, 5, 8, 130, 44].filter((element)=> {
return element >= 10;
});
// output [12, 130, 44]
flat && flatMap
let array = arr.flat([depth])
参数
- depth[可选] 指定要提取嵌套数组的结构深度,默认值为 1。
let array = arr.flatMap(function callback(currentValue[, index[, array]]) {
return currentValue
}[, thisArg]
参数
- callback
- currentValue 当前正在数组中处理的元素
- index[可选] 当前元素索引
- array[可选] 被调用的数组
- thisArg[可选]
兼容性
- IE不支持
特点
- flat()会移除数组中的空项;
- flatMap()等同于map()加深度depth为1的flat();
用例
[1, 2, [3, 4]].flat()
// output [1, 2, 3, 4]
[1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]].flat(5);
// output [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, , 4, 5].flat()
// output [1, 2, 3, 4]
let arr1 = ["it's Sunny in", "", "California"];
arr1.flatMap(x => x.split(" "));
// output ["it's","Sunny","in", "", "California"]
join
var str = arr.join([separator])
参数
- separator[可选] 指定的字符串分隔符
特点
- 当length为0,则返回空字符串
用例
var arr = ['Wind', 'Rain', 'Fire'];
arr.join(); // output "Wind,Rain,Fire"
arr.join(', '); // output "Wind, Rain, Fire"
arr.join(''); // output "WindRainFire"
push && unshift && pop && shift
let str = arr.pop() | arr.shift()
let length = arr.push(element1,...,elementN) | arr.unshift(element1,...,elementN)
参数
- elementN 被添加到数组末尾的元素。
特点
- pop(),shift()返回删除的值,当数组为空时返回undefined
- push(),unshift()返回更新后的length
- 均改变原数组
用例
const arr1 = ['one','two','three','four'];
const arr2 = ['three','four'];
//模拟进栈出栈
arr1.push('five','six') // output 6
arr1.pop() // output "four""
arr2.unshift('one','two'); // output 4
arr2.shift(); // output "one"
slice
let array = arr.slice([begin[, end]])
参数
- begin[可选] 开始的索引
- 默认为0
- 负数表示从原数组中的倒数第几个元素开始提取
- 超出原数组的索引范围则返回空数组
- end[可选] 终止的索引,且不包含end本身
- 省略,则 slice 会一直提取到原数组末尾
- 负数表示从原数组中的倒数第几个元素开始提取
- 大于数组的长度,slice 也会一直提取到原数组末尾
特点
- 返回浅拷贝的数组
用例
var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
fruits.slice(1, 3); // output ['Orange','Lemon']
扩展
根据规范,使用 Array.prototype.slice 转换宿主对象(如 DOM 对象)时,不必遵循 Mozilla 的默认行为,即可以转化任何符合条件的伪数组宿主对象为数组,IE < 9 没有遵循,而 IE9 + 遵循这个行为
splice
let array = arr.splice(start[, deleteCount[, item1[, item2[, ...]]]])
参数
- start 开始索引
- 超出数组长度,则从末尾开始添加内容
- 负数,则表示从数组末尾开始的第几位,当绝对值大于数组长度,则为0
- deleteCount[可选] 要移除的数组元素的个数
- 省略或大于start之后的元素总数,则start以后都被删除
- 0或者负数,则不移除元素
- itemN[可选] 要添加的元素,如不指定,则只删除数组元素
兼容性
- IE不支持
特点
- 返回被删除的元素组成的一个数组,没有删除则返回空数组
- 如果添加进数组的元素个数不等于被删除的元素个数,数组的长度会发生相应的改变
- 改变原数组
用例
const arr = ['one','two','three','four'];
arr.splice(-3,1,2) // output ["two"] arr=['one',2,'three','four']
arr.splice(-2,1,3,4) // output ["three"] arr=['one',2,3,4,'four']
arr.splice(-1,9) // output ["four"] arr=["one", 2, 3, 4]
reduce && reduceRight
let array = arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]) | arr.reduceRight(callback(accumulator, currentValue[, index[, array]])[, initialValue])
参数
- callback 指定某种顺序进行排列的函数,如果省略元素按照转换为的字符串的各个字符的Unicode位点进行排序。
- accumulator 累计器; 它是上一次调用回调时返回的累积值,或initialValue
- currentValue 数组中正在处理的元素
- index[可选] 当前元素的索引
- array[可选] 调用reduce()的数组
- initialValue[可选] 作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素,在没有初始值的空数组上调用 reduce 将报错。
兼容性
- IE9+
特点
- 返回函数累计处理的结果
- 如果数组仅有一个元素并且没有提供initialValue,或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行
用例
var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
// reduce() 没有初始值
[ { x: 2 }, { x: 22 }, { x: 42 } ].reduce( maxCallback ); // output NaN
[ { x: 2 }, { x: 22 }].reduce( maxCallback ); // output 22
[ { x: 2 }].reduce( maxCallback ); // output { x: 2 }
[].reduce( maxCallback ); // output TypeError
扩展
reduce可以说非常强大,可以使用reduce来实现map,flat,filter,some,every,find,findIndex等等方法,可以说reduce在手,数组不怕[叉腰]。
// 实现flat
[[0, 1], [2, 3], [4, 5]].reduce((a, b)=> {
return a.concat(b);
}, []);
// 实现filter
[0, 1, 2, 3, 4, 5].reduce((a, b)=> {
return b>=3?a.concat(b):a;
}, []);
// 实现some
[0, 1, 2, 3, 4, 5].reduce((a, b)=> b===3 || a, false);
// 实现every
[0, 1, 2, 3, 4, 5].reduce((a, b)=> b<=5 && a, true);
//其他原理一样
sort
let array = arr.sort([compareFunction])
参数
- compareFunction[可选] 指定某种顺序进行排列的函数,如果省略元素按照转换为的字符串的各个字符的Unicode位点进行排序。
- firstEl 第一个用于比较的元素。
- secondEl 第二个用于比较的元素。
- 返回值小于0 firstEl在前, 等于0位置不变,大于0 secondEl在前 快速记忆 小到大排序firstEl-secondEl,大到小排序secondEl-firstEl
特点
- 返回排序后的数组
- 改变原数组
用例
const arr = [40, 1, 5, 200]
arr.sort() // output [1, 200, 40, 5]
arr.sort((a,b)=>a-b) // output [1, 5, 40, 200]
arr.sort((a,b)=>b-a) // output [200, 40, 5, 1]
toString && toLocaleString
let str = arr.toString() | arr.toLocaleString([locales[,options]])
参数
- locales[可选] 带有BCP 47语言标记的字符串或字符串数组
- options[可选] 一个可配置属性的对象,对于数字 Number.prototype.toLocaleString(),对于日期Date.prototype.toLocaleString().
兼容性
- toLocaleString() IE不支持
特点
- 返回表示数组元素的字符串
- toLocaleString()使用locales和options时,数组中的元素将会使用各自的 toLocaleString 方法
用例
var prices = ['¥7', 500, 8123, 12];
prices.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' });
// output "¥7,¥500,¥8,123,¥12"
copywithin
var array = arr.copyWithin(target[, start[, end]])
参数
- target 0为基底的索引,复制序列到该位置
- 当为负数,target 将从末尾开始计算
- 当target >= arr.length,将会不发生拷贝。
- 如果target在start之后,复制的序列不会超过arr.length
- start[可选] 如果target在start之后,复制的序列不会超过arr.length
- end[可选] 0为基底的索引,开始复制元素的结束位置
- 拷贝到该位置,但不包括 end 这个位置的元素
- 当为负数, end将从末尾开始计算
- 如果为空,将会一直复制至数组结尾(默认为arr.length
快速记忆: 前开后闭,倒数写负数,最大为length值。
兼容性
- IE不支持
特点
- 浅复制数组的一部分到同一个数组中的另一个位置并返回
- 不会改变原来数组的长度
- 改变原数组
用例
const array1 = ['a', 'b', 'c', 'd', 'e'];
// 复制索引为3位置的数据到索引为0位置
console.log(array1.copyWithin(0, 3, 4));
// output: Array ["d", "b", "c", "d", "e"]
// 复制索引为3之后的数据到索引为1位置上
console.log(array1.copyWithin(1, 3));
// output: Array ["d", "d", "e", "d", "e"]
// 复制索引为2之后的数据到索引为4位置上,显然复制的长度超过了可容纳长度,
// 但由于不会改变原来数组的长度所以最后只复制了'c'元素
console.log(array1.copyWithin(4, 2));
// output: Array ['a', 'b', 'c', 'd', 'c']
扩展
copyWithin函数被设计为通用式的,其不要求其 this 值必须是一个数组对象。它不会改变 this 的长度 length,但是会改变 this 本身的内容,且需要时会创建新的属性。
用例
[].copyWithin.call({length: 5, 3: 3}, 0, 3);
// output {0: 3, 3: 3, length: 5}
[].copyWithin.call({length: 5, 3: 3,5:5}, 0, 3);
// output {0: 3, 3: 3, 5: 5, length: 5}
[].copyWithin.call({length: 5, 3: 3, 4: 4, 5: 5}, 0, 3);
// output {0: 3, 1: 4, 3: 3, 4: 4, 5: 5, length: 5}
//因为length为5,所以最后至复制了{3: 3, 4: 4}到索引为0位置
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// output Int32Array [4, 2, 3, 4, 5]
entries && values && keys
arr.entries() | arr.values() | arr.keys()
兼容性
- IE不支持
特点
- entries 返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
- values 返回一个新的 Array Iterator对象,该对象包含数组每个索引的值。
- keys 返回一个包含数组中每个索引键的Array Iterator对象。
用例
const array = ['a', 'b', 'c'];
const iterator1 = array.entries();
const iterator2 = array.values()
const iterator3 = array.keys()
console.log(iterator1.next().value);
// output: Array [0, "a"]
console.log(iterator1.next().value);
// output: Array [1, "b"]
console.log(iterator2.next());
// output: Object { value: "a", done: false }
console.log(iterator2.next());
// output: Object { value: "b", done: false }
console.log(iterator3.next());
// output Object { value: 0, done: false }
console.log(iterator3.next());
// output Object { value: 1, done: false }
注:这里主要使用next方法进行便利迭代器,Array Iterator还可以for..of遍历。
小结
- 除了for遍历数组,我们还能使用some,every,forEarch,map,find,findIndex,filter,reduce,reduceRight进行遍历数组。其中除了forEarch,map,filter,reduce,reduceRight不能结束循环外,其余均可返回Boolean值进行结束循环。
- 查找某个值是否存在数组中时,我们可以使用some,find,findIndex,includes,indexOf,lastIndexOf,reduce,reduceRight。
- 会改变原数组的方法有:sort,splice,push,pop,unshift,shift,copywithin。
- join可将数组转为字符串。
- 取数组中的某一段数据可以使用slice,filter,reduce,reduceRight。
- 扁平化数组使用flat,flatMap,reduce,reduceRight。
- from转换类数组为数组。