« 回到博客列表

每天一点ES6(8):数组的扩展

Tags: es6, array

久违了的更新

不知不觉几个月就过去了,终于想到要更新了,下一次又不知道要等到什么时候了,毕竟连猴年马月都过去了……

这一回我们来说说 ES6 中的数组。其实数组方面并没有太多实质性的改变,更多的是一些语法糖,对 ES5 语法的小修小补,虽没有惊天地泣鬼神的黑科技,但有糖吃总不是什么坏事。

Array.from()

用于将类数组对象和ES6中的“可遍历对象”转换为真正的数组,事实上只要是部署了Iterator接口的数据结构都可以被Array.from()转换为真正的数组。

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']

// 纯数组返回自身
Array.from([1, 2, 3])
// [1, 2, 3]

// 另类的循环重复
Array.from({ length: 2 }, () => 'jack')
// ['jack', 'jack']

// 字符串转数组后返回长度,能正确处理双字节Unicode字符
function countSymbols(string) {
  return Array.from(string).length;
}

需要注意的是,类数组对象区别于普通对象的本质区别在于length属性,因此任何具有length属性的对象理论上都能被该方法转成数组。

Array.from()还可以接受一个回调函数作为第二个参数,类似Array.map()的效果。配合 ES6 新引入的箭头函数,可以让代码优雅很多,免除了额外的forEach()map()

Array.of()

将参数列表中的元素组合成一个数组,主要目的是为了解决Array()构造函数接受到不同个数的参数时行为不一致的问题。

// Array() 面对不同个数的参数行为不统一
  Array()             // []
  Array(3)            // [, , ,]
  Array(3, 11, 8)     // [3, 11, 8]

  // Array.of() 单纯返回参数列表中元素组成的数组,面对不同个数的参数行为完全统一
  // 可以用它来代替 new Array()
  Array.of()          // []
  Array.of(3)         // [3]
  Array.of(3, 11, 8)  // [3,11,8]

  // ES5 的实现
  function ArrayOf(){
    return [].slice.call(arguments);
  }

copyWithin(target, start=0, end=this.length)

该方法用于在数组内部进行覆盖替换,第一个参数指定被替换内容的开始位置,后两个参数指定用于替换的内容的起止位置(注意end表示从这个索引开始不作为替换内容),皆为可选,负数表示倒过来数。

// 将3号位复制到0号位
  [1, 2, 3, 4, 5].copyWithin(0, 3, 4)
  // [4, 2, 3, 4, 5]

  // -2相当于3号位,-1相当于4号位
  [1, 2, 3, 4, 5].copyWithin(0, -2, -1)
  // [4, 2, 3, 4, 5]

  // 将3号位(开始到结束的内容)复制到0号位
  [].copyWithin.call({length: 5, 3: 1}, 0, 3)
  // {0: 1, 3: 1, length: 5}

  // 将2号位到数组结束,复制到0号位
  var i32a = new Int32Array([1, 2, 3, 4, 5]);
  i32a.copyWithin(0, 2);
  // Int32Array [3, 4, 5, 4, 5]

  // 对于没有部署TypedArray的copyWithin方法的平台
  // 需要采用下面的写法
  [].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
  // Int32Array [4, 2, 3, 4, 5]

find() & findIndex()

find()用于在数组中筛选出第一个符合条件的元素,参数为一个回调函数,指定筛选条件,对数组成员挨个执行该函数,返回第一个满足条件的元素, 找不到则返回undefined

findIndex()find()用法相同,但返回的是第一个满足条件的元素的索引,找不到则返回-1

这两个方法还弥补了indexOf()无法处理NaN的不足。

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

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

[NaN].indexOf(NaN)                       // -1
[NaN].findIndex(y => Object.is(NaN, y))  // 0

fill()

该方法使用给定值填充数组,可用于空数组的初始化,第一个参数是用于填充的内容,可选低2、3个参数指定填充的起止位置

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

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

  ['a', 'b', 'c'].fill(7, 1, 2)
  // ['a', 7, 'c']

keys()、values()、entries()

返回一个数组遍历器对象,内容分别为数组的索引、数值、键值对,可以用for...of遍历

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()

用于检测数组中是否包含指定项,接受第二个参数作为开始位置,负数表示倒过来数。该函数可作为indexOf()的替代品,更加语义化,且能够良好的处理NaN

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

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

数组的空位

指的是数组中不含任何值的位置(undefined也是有效值,不算空位),ES5 中的数组方法在处理空位时的行为非常不一致,ES6 统一将空位视为undefined,更加标准化。当然最理想的方案还是尽可能的避免空位的产生。

flat()、flatMap()

flat用于将一个多维数组拉平到更低的维度,默认向下拉平一层,可以传入一个正整数表示需要降维多少层。flat最多只能把数组拉平到一位数组,如果传入的参数比数组维度更高,也不会又额外的作用,传入 Infinity 可以拉平一切数组(数组中的对象不会被展开,还是对象)

flatMap相当于先对数组执行map(),在对新数组执行一层flat(),注意只有拉平一层,没得选。flatMap可以接受两个参数,第一个参数和map一样是个遍历函数,第二个参数是一个可选的this,用来绑定遍历函数中的this

该系列的其他文章

上一篇:每天一点ES6(7):数值的扩展

下一篇:每天一点ES6(9):函数的扩展