Array原型方法整理

这些方法基本都是ES5版本添加的,IE9起实现。

Array.from()

该方法从一个类似数组或可迭代对象中创建一个新的,浅拷贝的数组实例。

基本

语法:

1
Array.from(arrayLike[, mapFn[, thisArg]])

参数:

  • arrayLike:想要转换成数组的伪数组对象或可迭代对象。
  • mapFn (可选参数):如果指定了该参数,新数组中的每个元素会执行该回调函数。
  • thisArg (可选参数):可选参数,执行回调函数 mapFn 时 this 对象。

返回值:

  • 一个新的数组实例

Array.from() 可以通过以下方式来创建数组对象:

  • 伪数组对象(拥有一个 length 属性和若干索引属性的任意对象)
  • 可迭代对象(可以获取对象中的元素,如 Map和 Set 等)

from() 的 length 属性为 1 ,即Array.from.length === 1

拷贝数组(浅拷贝)


1
2
3
4
5
let arr = [1, 2, 3];
let arr2 = Array.from(arr);

console.log(arr2); // [1, 2, 3]
console.log(arr2 === arr); // false

其他情况

Array from a String

1
2
Array.from('foo'); 
// ["f", "o", "o"]

Array from a Set

1
2
3
let s = new Set(['foo', window]); 
Array.from(s);
// ["foo", window]

Array from a Map

1
2
3
let m = new Map([[1, 2], [2, 4], [4, 8]]);
Array.from(m);
// [[1, 2], [2, 4], [4, 8]]

Array from an Array-like object (arguments)

1
2
3
4
5
6
7
function f() {
return Array.from(arguments);
}

f(1, 2, 3);

// [1, 2, 3]

在Array.from中使用箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
// Using an arrow function as the map function to
// manipulate the elements
Array.from([1, 2, 3], x => x + x);
// x => x + x代表这是一个函数,只是省略了其他的定义,这是一种Lambda表达式的写法
// 箭头的意思表示从当前数组中取出一个值,然后自加,并将返回的结果添加到新数组中
// [2, 4, 6]


// Generate a sequence of numbers
// Since the array is initialized with `undefined` on each position,
// the value of `v` below will be `undefined`
Array.from({length: 5}, (v, i) => i);
// [0, 1, 2, 3, 4]

数组去重合并

1
2
3
4
5
6
7
function combine(){ 
let arr = [].concat.apply([], arguments); //没有去重复的新数组
return Array.from(new Set(arr));
}

var m = [1, 2, 2], n = [2,3,3];
console.log(combine(m,n)); // [1, 2, 3]

Array.of()

该方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。

基本

语法:

1
Array.of(element0[, element1[, ...[, elementN]]])

参数:

  • elementN:任意个参数,将按顺序成为返回数组中的元素。

返回值:

  • 新的 Array 实例。
1
2
3
Array.of(1);         // [1]
Array.of(1, 2, 3); // [1, 2, 3]
Array.of(undefined); // [undefined]

Array.prototype.every()

该方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。

基本

语法:

1
arr.every(callback[, thisArg])

参数:

  • callback:用来测试每个元素的函数,它可以接收三个参数:
    • element:用于测试的当前值。
    • index(可选):用于测试的当前值的索引。
    • array(可选):调用 every 的当前数组。
  • thisArg:执行 callback 时使用的 this 值。

返回值:

  • 如果回调函数的每一次返回都为 truthy 值,返回 true ,否则返回 false。

若收到一个空数组,此方法在一切情况下都会返回 true。

every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个会使 callback 返回 falsy 的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 true,every 就会返回 true。callback 只会为那些已经被赋值的索引调用。不会为那些被删除或从未被赋值的索引调用。

检测所有数组元素的大小

如:

1
2
3
4
5
function isBigEnough(element, index, array) {
return element >= 10;
}
[12, 5, 8, 130, 44].every(isBigEnough); // false
[12, 54, 18, 130, 44].every(isBigEnough); // true

Array.prototype.fill()

该方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。

基本

语法:

1
arr.fill(value[, start[, end]])

参数:

  • value:用来填充数组元素的值。
  • start(可选):起始索引,默认值为0。
  • end(可选):终止索引,默认值为 this.length。

返回值:

  • 修改后的数组

如果 start 是个负数, 则开始索引会被自动计算成为 length+start, 其中 length 是 this 对象的 length 属性值。如果 end 是个负数, 则结束索引会被自动计算成为 length+end。

fill 方法故意被设计成通用方法, 该方法不要求 this 是数组对象。
fill 方法是个可变方法, 它会改变调用它的 this 对象本身, 然后返回它, 而并不是返回一个副本。
当一个对象被传递给 fill方法的时候, 填充数组的是这个对象的引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[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); // [4, 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]
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}

// Objects by reference.
var arr = Array(3).fill({}) // [{}, {}, {}];
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]

注意fill引用类型

当给fill传递一个入参是引用类型的时候,那么fill在填充坑位时填充的其实是入参的引用。所以会发生如下情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// example 1
let arr1 = (new Array(3)).fill([]);
arr1[0][0] = 1;
console.log(arr1);
/*
example 1 result:
[
[1],
[1],
[1]
]
*/

// example 2
let arr2 = (new Array(3)).fill({});
arr2[0].a = 1;
console.log(arr2);
/*
example 2 result:
[
{a: 1},
{a: 1},
{a: 1}
]
*/

因此如果要fill引用类型的话,可以通过循环遍历,或者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// example 1
let arr1 = (new Array(3)).fill(0).map(item => new Array());
arr1[0][0] = 1;
console.log(arr1);
/*
example 1 result:
[
[1],
[],
[]
]
*/

// example 2
let arr2 = (new Array(3)).fill(0).map(item => new Object());
arr2[0].a = 1;
console.log(arr2);
/*
example 2 result:
[
{a: 1},
{},
{}
]
*/

Array.prototype.filter()

该方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。

基本

语法:

1
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])

参数:

  • callback:用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留。它接受以下三个参数:
  • element:数组中当前正在处理的元素。
  • index(可选):正在处理的元素在数组中的索引。
  • array(可选):调用了 filter 的数组本身。
  • thisArg(可选):执行 callback 时,用于 this 的值。

返回值:

  • 一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。

filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。

filter 遍历的元素范围在第一次调用 callback 之前就已经确定了。在调用 filter 之后被添加到数组中的元素不会被 filter 遍历到。如果已经存在的元素被改变了,则他们传入 callback 的值是 filter 遍历到它们那一刻的值。被删除或从来未被赋值的元素不会被遍历到。

筛选排除所有较小的值


1
2
3
4
5
function isBigEnough(element) {
return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]

过滤 JSON 中的无效条目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var arr = [
{ id: 15 },
{ id: -1 },
{ id: 0 },
{ id: 3 },
{ id: 12.2 },
{ },
{ id: null },
{ id: NaN },
{ id: 'undefined' }
];

var invalidEntries = 0;

function isNumber(obj) {
return obj !== undefined && typeof(obj) === 'number' && !isNaN(obj);
}

function filterByID(item) {
if (isNumber(item.id) && item.id !== 0) {
return true;
}
invalidEntries++;
return false;
}

var arrByID = arr.filter(filterByID);

console.log('Filtered Array\n', arrByID);
// Filtered Array
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]

console.log('Number of Invalid Entries = ', invalidEntries);
// Number of Invalid Entries = 5

在数组中搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var fruits = ['apple', 'banana', 'grapes', 'mango', 'orange'];

/**
* Array filters items based on search criteria (query)
*/
function filterItems(query) {
return fruits.filter(function(el) {
return el.toLowerCase().indexOf(query.toLowerCase()) > -1;
})
}

console.log(filterItems('ap')); // ['apple', 'grapes']
console.log(filterItems('an')); // ['banana', 'mango', 'orange']

// es6 实现
const fruits = ['apple', 'banana', 'grapes', 'mango', 'orange'];

/**
* Array filters items based on search criteria (query)
*/
const filterItems = (query) => {
return fruits.filter((el) =>
el.toLowerCase().indexOf(query.toLowerCase()) > -1
);
}

console.log(filterItems('ap')); // ['apple', 'grapes']
console.log(filterItems('an')); // ['banana', 'mango', 'orange']

Array.prototype.flat()

该方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。

基本

语法:

1
var newArray = arr.flat(depth)

参数:

  • depth(可选):指定要提取嵌套数组的结构深度,默认值为 1。

返回值:

  • 一个包含将数组与子数组中所有元素的新数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]

var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]

var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]

//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]

扁平化与空项

flat() 方法会移除数组中的空项:

1
2
3
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]

替代实现

一层

1
2
3
4
5
6
7
8
var arr1 = [1, 2, [3, 4]];
arr1.flat();

// 反嵌套一层数组
arr1.reduce((acc, val) => acc.concat(val), []);// [1, 2, 3, 4]

// 或使用 ...
const flatSingle = arr => [].concat(...arr);

多层

1
2
3
4
5
6
7
8
// 使用 reduce、concat 和递归无限反嵌套多层嵌套的数组
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];

function flattenDeep(arr1) {
return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
flattenDeep(arr1);
// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

Array.prototype.reduce()

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

基本

语法:

1
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

参数:

  • callback:执行数组中每个值的函数,包含四个参数:
    • accumulator:累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
    • currentValue:数组中正在处理的元素。
    • currentIndex(可选):数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则为1。
    • array(可选):调用reduce()的数组
  • initialValue(可选)作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。

返回值:

  • 函数累计处理的结果

如果数组为空且没有提供initialValue,会抛出TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。

数组里所有值的和

1
2
3
4
5
6
7
8
9
10
var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
return accumulator + currentValue;
}, 0);
// 和为 6

// ES6
var total = [ 0, 1, 2, 3 ].reduce(
( acc, cur ) => acc + cur,
0
);

将二维数组转化为一维

1
2
3
4
5
6
7
8
9
10
11
12
13
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
function(a, b) {
return a.concat(b);
},
[]
);
// flattened is [0, 1, 2, 3, 4, 5]

// ES6
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
( acc, cur ) => acc.concat(cur),
[]
);

计算数组中每个元素出现的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

var countedNames = names.reduce(function (allNames, name) {
if (name in allNames) {
allNames[name]++;
}
else {
allNames[name] = 1;
}
return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

相关链接