/ ECMAScript6

ECMAScript 6 之数组

标签: ECMAScript 6 javaScript

Array.from

javascript 中有这样一类的存在:类数组,它不是数组,却能像数组那么操作,如下便是一个类数组结构。

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

类数组结构,能像数组哪样取值、 for 循环,但是却不能适用数组 forEach/splice 等数组特定的方法,在 ES5 中必须使用一些特殊的方法来将一个类数组结构转化成数组,而在 ES6 中, Array 对象下提供了 form 方法,该方法用于将一个类数组结构转化成一个真正的数组。

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

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

一些类数组使用实例:

  • 通过 DOM 操作返回的 NodeList 集合;
let ps = document.querySelectorAll('p')

//只有将ps转化成一个真正的数组才能使用forEach方法
Array.from(ps).forEach(function (p) {
  console.log(p)
});
  • 函数内部的 arguments 对象
// arguments对象
function foo() {
  var args = Array.from(arguments)
  console.log(args)
}
  • 将一个字符串转换成一个数组
var sArr = Array.from('hello')
console.log(aArr)
// ['h', 'e', 'l', 'l', 'o']
  • Set集合
let namesSet = new Set(['a', 'b'])
Array.from(namesSet) // ['a', 'b']

注: 只要是部署了 Iterator 接口的结构,都可以使用。

当然对一个数组使用 Array.from 是没有任何问题,只会将原来的数组结构复制一遍,并返回一个新的数组。(感觉可以用这个来复制数组)

同时 Array.from 还可以接受第二个参数,作用类似与数组的 map 方法,用来对每个元素进行处理,然后返回一个新的数组。

Array.from(arrayLike, x => x * x)

// 等同于
Array.from(arrayLike).map(x => x * x)

Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
  • 实例1:取一组 DOM 节点的文本内容
let spans = document.querySelectorAll('span.name')
let names2 = Array.from(spans, s => s.textContent)
  • 实例2:将数组中布尔值为 false 的成员转为 0
Array.from([1, , 2, , 3], (n) => n || 0)
// [1, 0, 2, 0, 3]
  • 实例3:返回各种数据的类型
function typesOf () {
  return Array.from(arguments, value => typeof value)
}
typesOf(null, [], NaN)
// ['object', 'object', 'number']
  • 实例4:只要有一个原始的数组结构就能构造出一个数组
Array.from({ length: 2 }, () => 'jack')
// ['jack', 'jack']

Array.of

用于将一组值,转化为一组值。

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

这个方法的主要目的,是弥补数组构造函数 Array() 的不足。因为参数个数的不同,会导致 Array() 的行为有差异。

Array.of 总是返回参数值组成的数组。如果没有参数,就返回一个空数组。

copyWithin()

用于在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。

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

注: 这里的 = 使用了函数中默认值的写法。

参数 说明
target (必需) 从该位置开始替换数据。
start (可选) 从该位置开始读取数据,默认为 0 。如果为负值,表示倒数。
end (可选) 到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]

更多的例子:

// 将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}

find() & findIndex()

方法 效果
find 方法用于找出第一个符合条件的数组成员
findIndex 方法用于找出第一个符合条件的数组成员的位置

参数都为一个函数,用于做判断

// 找出第一个值小于0的数
[1, 4, -5, 10].find((n) => n < 0)
// -5

// 找出第一个值大于9的数
[1, 5, 10, 15].find((value, index, arr) => {
    return value > 9
}) // 10

// 找出第一个大于9的数的位置
[1, 5, 10, 15].findIndex((value, index, arr) => {
    return value > 9
}) // 2

若没有值符合,两个方法的返回值都为 -1

fill()

使用给定值,填充一个数组。

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

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

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

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

entries() & keys() & values()

方法 效果
entries 对键值对的遍历
keys 对键名的遍
values 对键值的遍历
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()

表示某个数组是否包含给定的值,与字符串的includes方法类似。

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

数组中的空位问题

ES5 中数组中的空位是一个让人头疼的问题,空位有可能被忽略,而不是当成 undefined 来处理,比如

  • forEach() , filter() , every()some() 都会跳过空位。
  • map() 会跳过空位,但会保留这个值
  • join()toString() 会将空位视为 undefined ,而 undefinednull 会被处理成空字符串。

这个情况在 ES6 中已经得到改善, ES6 规定空位转化为 undefined ,所以在以上内容中的所有方法以及 ES6 中所用用到数组的地方,空位都会被当成 undefined 来处理。

Array.from(['a',,'b'])
// [ "a", undefined, "b" ]

[,'a','b',,].copyWithin(2, 0) // [,"a",,"a"]

let arr = [, ,]
for (let i of arr) {
    console.log(1);
}
// 1
// 1

注: 上面的例子大多数来自 《ECMAScript 6入门》这本书。