看完这篇你还敢说不熟悉数组操作?

132 阅读15分钟

数组是前端工程师们最常用到的数据集合之一,掌握好了数组使用犹如获得神兵利器, 方便我们处理得到想要的数据和结构,提高工(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转换类数组为数组。