ES6系列 数组的扩展

713 阅读6分钟

往期内容

1.扩展运算符

扩展运算符(spread)是三个点 (...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

console.log(...[1, 2, 3])
// 1 2 3

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5

[...document.getElementsByClassName('tag')]
// [<div>, <div>, <div>]

扩展运算符与正常的函数参数可以结合使用,非常灵活。

function test(v, w, x, y, z) { }
const args = [0, 1];
test(-1, ...args, 2, ...[3]);

扩展运算符后面还可以放置表达式。

const arr = [
  ...(2 > 0 ? ['a'] : []),
  'b',
];
// ['a', 'b']

如果扩展运算符后面是一个空数组,则不产生任何效果。

[...[], 1]
// [1]

2.替代函数的 apply 方法

由于扩展运算符可以展开数组,所以不再要apply方法,将数组转为函数的参数了。

// ES5 的写法
function test(x, y, z) {
  // ...
}
var args = [0, 1, 2];
test.apply(null, args);

// ES6的写法
function test1(x, y, z) {
  // ...
}
let args1 = [0, 1, 2];
test1(...args);

3.扩展运算符的应用

3.1 复制数组

数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。

const array = [1, 2];
const array1 = array;

array1[0] = 2;
consloe.log(array1)  // [2, 2]

上面代码中, array1 并不是array的克隆,而是指向同一份数据的另一个指针。修改array1,会直接导致array的变化。

ES5 只能用变通方法来复制数组。

const array = [1, 2];
const array1 = array.concat();

array1[0] = 2;
console.log(array) // [1, 2]

上面代码中,array 会返回原数组的克隆,再修改 array1 就不会对 array 产生影响。

扩展运算符提供了非常常用并且简单的复制数组的简便写法。

const array = [1, 2];
// 写法一
const array1 = [...array];
// 写法二
const [...array1] = array;

上面的两种写法,都是扩展运算符的简单写法,非常的实用

3.2 合并数组

扩展运算符提供了数组合并的新写法。

大家可以想一下,没有ES5的时候,合并数组是怎么搞的,不过哪些都不重要了,人往高处走。

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

不过,这两种方法都是浅拷贝,使用的时候需要注意。

const array1 = [{ foo: 1 }];
const array2 = [{ bar: 2 }];

const array3 = array1.concat(array2);
const array4 = [...array1, ...array2];

array3[0] === array1[0] // true
array4[0] === array2[0] // true

上面代码中,array3和array4是用两种不同方法合并而成的新数组,但是它们的成员都是对原数组成员的引用,这就是浅拷贝。如果修改了原数组的成员,会同步反映到新数组。

3.3 与解构赋值结合

扩展运算符可以与解构赋值结合起来,用于生成数组。

const [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first) // 1
console.log(rest)  // [2, 3, 4, 5]

const [first, ...rest] = [];
console.log(first) // undefined
console.log(rest)  // []

const [first, ...rest] = ["foo"];
console.log(first)  // "foo"
console.log(rest)   // []

3.4 字符串

扩展运算符还可以将字符串转为真正的数组。

[...'hello']
// [ "h", "e", "l", "l", "o" ]

3.5Map 和 Set 结构

扩展运算符内部调用的是数据结构的 Iterator 接口,因此只要具有 Iterator 接口的对象,都可以使用扩展运算符,比如 Map 结构。

let map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

let arr = [...map.keys()]; // [1, 2, 3]

4.Array.from()

Array.from()方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

下面是一个类似数组的对象,Array.from()将它转为真正的数组。

let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
};

// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

实际应用中,常见的类似数组的对象是 DOM 操作返回的 NodeList 集合。

// NodeList对象
let ps = document.querySelectorAll('p');
Array.from(ps).filter(p => {
  return p.textContent.length > 100;
});


Array.from('hello')
// ['h', 'e', 'l', 'l', 'o']

let namesSet = new Set(['a', 'b'])
Array.from(namesSet) // ['a', 'b']

如果参数是一个真正的数组,Array.from()会返回一个一模一样的新数组。

Array.from([1, 2, 3])
// [1, 2, 3]

值得提醒的是,扩展运算符(...)也可以将某些数据结构转为数组。

// arguments对象
function foo() {
  const args = [...arguments];
}

// NodeList对象
[...document.querySelectorAll('div')]

5.Array.of()

Array.of()方法用于将一组值,转换为数组。

Array.of(3, 11, "8") // console.log([3,11,"8"])
Array.of(3) // console.log([3])
Array.of(3).length //console.log(1)

6.数组实例的 find() 和 findIndex()

数组的find方法,用于找出第一个符合条件的数组成员。参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,并且返回该成员。如果没有符合条件的成员,则返回undefined。

console.log([1, 4, -5, 10].find((i) => i === 4))

其实find是一个回调函数

[8, 9, 10, 5].find(function(value, index, arr) {
  return value > 9;
}) // 10

当前方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。

其实findIndex方法与find方法挺相似的返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,返回-1.

7.数组实例的 fill()

fill()方法使用给定值,填充一个数组,你可以简单的理解fill() 是个站坑的

['a', 'b', 'c'].fill(3)
// [3,3,3]

new Array(3).fill(5)
// [5,5,5]

上面操作显示该方法用于空数组的初始化占坑非常方便。数组中已有的数据,会被全部抹去。

方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置

[1, 2, 2, 3].fill(6, 1, 3);
//[1,6,63]

8.数组实例的 includes()

includes()方法返回一个布尔值,表示某个数组是否包含给定的值

[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4)     // false
[1, 2, NaN].includes(NaN) // true

该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3)则会重置为从0开始。

[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true

9.数组实例的 flat()、sort()

数组的成员有时还是嵌套数组,flat()用于将嵌套的数组解构,变成普通数组。该方法返回一个新数组,对原数据没有影响。

[1, 2, [3, 4,5,6,7,8]].flat() // [1, 2, 3, 4, 5, 6, 7, 8]

上面代码中,原数组的成员里面有一个数组,flat()方法将子数组的成员取出来,添加在原来的位置。

sort() 排序大家应该都不陌生吧。

[10, 2, 12, 4, 5, 10, 78, 5, 5, 55, 96, 2].sort((a,b)=>{ return a>b?1:-1})
//  [2, 2, 4, 5, 5, 5, 10, 10, 12, 55, 78, 96]
[10, 2, 12, 4, 5, 10, 78, 5, 5, 55, 96, 2].sort((a,b)=>{ return a<b?1:-1})
//  [96, 78, 55, 12, 10, 10, 5, 5, 5, 4, 2, 2]

下面是我的公众号大家一起写文章呀。