Array.of()和Array.from()
ES6新增了二种方法:Array.of()
和Array.from()
,它们有什么用途呢?
Array.of
ES6之前,有两种构建数组的方式,一种是数组字面量
,一种是构造函数Array
。但是,构造函数在设计时存在一个缺陷(怪癖),如果只传一个数字,那么指定的是数组的长度,而不是填充的值。为了弥补这个问题,设计组没有在原有基础上直接更改,而是重新推出了一个新方法of()来解决这个问题。可以这么说,of()方法的是作为一个救火队员
的身份出现的:
Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
Array(7); // [ , , , , , , ]
Array(1, 2, 3); // [1, 2, 3]
如上,Array(7)得到的是长度为7的数组,每一项都为空,这不符合我们的本意,我们的本意是想创建一个长度为1的数组(其中只有一项为数字类型7),但构造函数的这个缺陷(怪癖)导致了歧义,而of()方法则很好地优化
了这个问题。
也许有人会说,如果一开始,构造函数Array的特征就设计得和现在的of()方法一样,或许就不需要用of()方法来弥补这个漏洞了,想法是美好的,现实是残酷的。你要知道,没有任何一门语言是完美的,尤其是对于JavaScript而言,它只用10天时间就被设计出来了!
接下来,我们再来看看Array.from()方法。
一个问题
首先,我们来看一个问题,需要创建一个共81项的数组,有9行,每行9个数(从1-9),在页面上进行展示,如下:
怎么做呢?可以这样:
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
arr = arr.concat(arr)
arr = arr.concat(arr)
arr = arr.concat(arr)
arr = arr.concat([1, 2, 3, 4, 5, 6, 7, 8, 9])
console.table(arr)
的确可以实现,但是真的不优雅,一种欠薪程序员的风格扑面而来!如果规模加大,需要的是810项的数组呢?那就需要换一种方式实现了:
let arr = Array.apply(null, { length: 810 })
.map((item, index) => {
return {
id: index,
number: index % 9 + 1
}
})
看上去是不错,但容易让人困惑,阅读起来很不直观,又是apply,又是null的,让人抓狂。
我们试试用ES6的Array.from
:
let arr = Array.from({ length: 810 }, (item, index) => ({
id: index,
number: index % 9 + 1
}))
代码量变少了,更重要的是,代码意图也更直观了,数组长度810,每一项按照约定的规则进行初始化。
注意:{length: 810}是一个类数组
对象。
Array.from
相信大家已经对from()有了大概的了解了,准确说,Array.from()
方法对一个类数组
或可迭代对象
创建一个新的,浅拷贝的数组实例。因为其本身是通过转化其他对象来获得数组的,所以,这个from命名倒是恰到好处。
我们来看看它的语法:
Array.from(arrayLike[, mapFn[, thisArg]])
arrayLike:想要转换成数组的伪数组对象或可迭代对象。
mapFn(可选):如果指定了该参数,新数组中的每个元素会执行该回调函数。
thisArg(可选):执行回调函数 mapFn 时 this 对象。
因此,可以通过以下方式来创建数组对象:
- 伪数组对象(拥有一个
length
属性和若干索引属性的任意对象) - 可迭代对象(可以获取对象中的元素,如 Map和 Set 等)
上面那个例子中,就是通过包含length属性的伪数组对象,来构建了一个长度810的数组。
我们再来看看通过可迭代对象构建数组的例子:
const set = new Set(['foo', 'bar', 'baz', 'foo']);
Array.from(set);
// [ "foo", "bar", "baz" ]
上面的set变量时一个可迭代对象,最终通过Array.from()获得了数组。
小结
所以说,Array.of()是对构造数组Array的优化,而Array.from()则是将伪数组对象或者可迭代对象转化为数组。