# 7. 数组的扩展

# 扩展运算符(...)

将一个数组转为用逗号分隔的参数序列,内部使用for...of循环,所以也可以用于 Set 结构

  • 函数rest参数 ...rest 是将传入的剩余部分参数转为数组,类似于扩展运算符的逆运算
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5

function add(x, y) {
  return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42
add.apply(null, numbers) // 42

// 代替apply写法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// ES5的 写法
Array.prototype.push.apply(arr1, arr2);
// ES6 的写法
arr1.push(...arr2);

// 复制数组
const a1 = [1, 2];
//写法1:
const a2 = [...a1];
//写法2:
const [...a2] = a1; // 与结构赋值结合起来

// 合并数组
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' ]

// 字符串转数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]

# Array.from()

用于将类似数组的对象和可遍历的对象(Set、Map等)转为真正的数组

let arrayLike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

Array.from('hello')
// ['h', 'e', 'l', 'l', 'o']
let namesSet = new Set(['a', 'b'])
Array.from(namesSet) // ['a', 'b']

// 第二个参数
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);

Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]

Array.from({ length: 2 }, () => 'jack')
// ['jack', 'jack']

// Array.from()的另一个应用是,将字符串转为数组,然后返回字符串的长度。因为它能正确处理各种 Unicode 字符,可以避免 JavaScript 将大于\uFFFF的 Unicode 字符,算作两个字符的 bug。
function countSymbols(string) {
  return Array.from(string).length;
}

# Array.of()

用于将一组数值,转换为数组

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

// 类似于
function ArrayOf(){
  return [].slice.call(arguments);
}

# find(), findIndex()

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

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

// 数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;}
) // 2

// 这两个方法都可以接受第二个参数,用来绑定回调函数的this对象。
function f(v){
  return v > this.age;
}
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person);    // 26

// 这两个方法都可以发现NaN,弥补了数组的indexOf方法的不足,indexOf方法无法识别数组的NaN成员,但是findIndex方法可以借助Object.is方法做到。
[NaN].indexOf(NaN)
// -1
[NaN].findIndex(y => Object.is(NaN, y))
// 0

# 数组的遍历方法entries(),keys()和values()

可以用for...of循环进行遍历,它们都返回一个遍历器对象(详见《Iterator》一章)。唯一的区别是keys()是对键名(数组下标)的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

for (let index of ['a', 'b'].keys()) {  
  console.log(index);}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
  console.log(elem);}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
  console.log(index, elem);}
// 0 "a"
// 1 "b"

# includes()

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

# 遍历数组时对空格的处理

// ES5 对空位的处理
// forEach(), filter(), reduce(), every() 和some()都会跳过空位
// map()会跳过空位,但会保留这个值
// join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串

// forEach方法
[,'a'].forEach((x,i) => console.log(i)); // 1
// filter方法
['a',,'b'].filter(x => true) // ['a','b']
// every方法
[,'a'].every(x => x==='a') // true
// reduce方法
[1,,2].reduce((x,y) => x+y) // 3
// some方法
[,'a'].some(x => x !== 'a') // false
// map方法
[,'a'].map(x => 1) // [,1]
// join方法
[,'a',undefined,null].join('#') // "#a##"
// toString方法
[,'a',undefined,null].toString() // ",a,,"

// ES6 则是明确将空位转为undefined。
// entries()
[...[,'a'].entries()] // [[0,undefined], [1,"a"]]
// keys()
[...[,'a'].keys()] // [0,1]
// values()
[...[,'a'].values()] // [undefined,"a"]
// find()
[,'a'].find(x => true) // undefined
// findIndex()
[,'a'].findIndex(x => true) // 0
上次更新: 2020/10/28 18:32:03