博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【译】在 JavaScript 中创建和填充任意长度的数组
阅读量:5903 次
发布时间:2019-06-19

本文共 3389 字,大约阅读时间需要 11 分钟。

原文链接:

创建数组的最佳方式是使用字面量:

const arr = [0,0,0];复制代码

但也不总是最佳方案,例如在创建大型数组时。这篇博客就探讨了在这些情况下该怎么做。

1. 没有空元素的数组往往表现更好

在大多数编程语言中,数组是连续的值序列。 在 JavaScript 中,Array 是一个将索引映射到元素的字典,它可以有空元素,而且空元素也有自己对应的索引,但它并不映射到元素上。例如下面这个数组就有一个空元素在索引 1 的位置上。

> Object.keys(['a',, 'c'])[ '0', '2' ]复制代码

没有空元素的数组称作密数组,密数组往往表现更好,因为它们可以连续(内部)存储。一旦至少有一个空元素,内部表示必须改变。有两种选择:

  • 字典,查找需要更多时间并且存储开销更大。
  • 连续的数据结构,具有空元素的标记值。检查值是否是一个空元素,需要额外的时间。在任何一种情况下,如果引擎遇到一个空元素,它不能只返回 undefined ,而必须遍历原型链并搜索一个名称为空元素索引的属性,这需要花费更多时间。

在某些引擎中,例如 V8,切换到性能较低的数据结构是永久性的。即使所有空元素都添加上值,它们也不会切换回来。

有关 V8 如何表现数组的更多信息,请参阅 Mathias Bynens 的 。

2. 创建数组

数组构造函数

使用数组构造函数来创建一个给定长度的数组是一个很普遍的事情。

const LEN = 3;const arr = new Array(LEN);assert.equal(arr.length, LEN);// arr only has holes in itassert.deepEqual(Object.keys(arr), []);复制代码

这种方法很方便,但它有两个缺点:

  • 即使您稍后用完全添上值,这些空元素也会使此数组略微变慢。
  • 空元素很少是元素的初始“值”。例如,0 更常见。

2.2 数组构造函数加上 .fill() 方法

.fill() 方法改变现有数组并使用指定值填充它。这有助于在通过新的 Array() 创建数组后初始化数组:

const LEN = 3;const arr = new Array(LEN).fill(0);assert.deepEqual(arr,[0,0,0]);复制代码

警告:如果你 .fill() 一个带有对象的数组,所有元素都引用同一个实例(即不会克隆该对象):

const LEN = 3;const obj = {};const arr = new Array(LEN).fill(obj);assert.deepEqual(arr, [{}, {}, {}]);obj.prop = true;assert.deepEqual(arr,  [ {prop:true}, {prop:true}, {prop:true} ]);复制代码

我们稍后会遇到一种没有这个问题的填充方法(通过 Array.from())。

2.3 .push() 方法

const LEN = 3;shuconst arr = [];for (let i=0; i < LEN; i++) {  arr.push(0);}assert.deepEqual(arr, [0, 0, 0]);复制代码

这一次,我们创建并填充了一个数组而没有在其中添加空元素。因此,在创建数组后使用数组应该比使用数组构造函数更快。唉,创建数组的速度较慢,因为引擎不得不随着它的增长多次重新分配连续的内部表示。

2.4 填充未定义的数组

Array.from()iterables类型 和 like-Array 类型 的值转换为数组。它将空元素视为未定义的元素。我们可以使用它将每个空元素转换为未定义的:

> Array.from({length: 3})[ undefined, undefined, undefined ]复制代码

参数 {length:3} 是一个类似于数组的对象,长度为3,只包含空元素。也可以使用 new Array(3) ,但通常会创建更大的对象。

数组扩展仅适用于 iterable 的值,并且与 Array.from() 具有类似的效果:

> [...new Array(3)][ undefined, undefined, undefined ] 复制代码

唉,Array.from() 通过 new Array() 创建它的结果,所以你仍然得到一个稀疏数组。

2.5 使用 Array.from() 映射

如果提供映射函数作为其第二个参数,则可以使用 Array.from() 进行映射。

使用值填充数组

  • 创建一个小整数的数组:
> Array.from({length:3},()=> 0)[0,0,0]复制代码
  • 使用唯一(非共享)对象创建数组:
> Array.from({length:3},()=>({}))[{},{},{}]复制代码

创建整数值范围

  • 使用升序整数创建数组:
> Array.from({length:3},(x,i)=> i)[0,1,2]复制代码
  • 创建任意整数范围:
> const START = 2,END = 5;> Array.from({length:END-START},(x,i)=> i + START)[2,3,4]复制代码
  • 使用升序整数创建数组的另一种方法是通过 .keys(),它也将漏洞看作是未定义的元素:
> [... new Array(3).keys()][0,1,2]复制代码

.keys() 返回一个可迭代的。我们使用扩展运算符将其转换为数组。

3. 补充:创建数组

  • 填充空元素或未定义:
new Array(3)→ [ , , ,]Array.from({length: 2})→ [undefined, undefined][...new Array(2)]→ [undefined, undefined]复制代码
  • 填充任意值:
const a=[]; for (let i=0; i<3; i++) a.push(0);→ [0, 0, 0]new Array(3).fill(0)→ [0, 0, 0]Array.from({length: 3}, () => ({}))→ [{}, {}, {}] (unique objects)复制代码
  • 整数范围:
Array.from({length: 3}, (x, i) => i)→ [0, 1, 2]const START=2, END=5; Array.from({length: END-START}, (x, i) => i+START)→ [2, 3, 4][...new Array(3).keys()]→ [0, 1, 2]复制代码

3.1 方法推荐

我更喜欢以下方法,重点是可读性,而不是性能。

  • 你需要创建一个你将完全填充的空数组,然后呢?
new Array(LEN)复制代码
  • 你需要创建一个用原始值初始化的数组吗?
new Array(LEN).fill(0)复制代码
  • 你需要创建一个用对象初始化的数组吗?
Array.from({length: LEN}, () => ({}))复制代码
  • 你需要创建一系列整数吗?
Array.from({length: END-START}, (x, i) => i+START)复制代码

如果您正在处理整数或浮点数的数组,请考虑 以此为目的创建的。它们不能有空元素,并且总是用零初始化。

提示: 数组性能通常没有那么重要

  • 在大多数情况下,我不会过分担心性能问题。即使是空元素的数组也非常快。我们可以更多得去考虑怎么让代码易于理解更有意义。

  • 此外,引擎优化的方式和位置也一直在发生变化。明天总是会比今天更快。

4. 致谢

感谢 Mathias Bynens 和 Benedikt Meurer 帮助我了解到 V8 细节。

5. 进一步阅读

  • “探索ES6”中的“”一章
  • “探索ES6”中的“”

转载于:https://juejin.im/post/5c8d839ce51d4577e94b35e1

你可能感兴趣的文章
从Oracle Public Yum为Oracle Linux建立本地的Yum源
查看>>
静态路由和默认路由
查看>>
关于阿里开发者招聘节 |这5道笔试真题 你会吗!???
查看>>
C#的异常处理机制
查看>>
vsftp:500 OOPS: could not bind listening IPv4 sock
查看>>
Linux安装BTCPayServer并设置比特币BTC和Lightning支付网关
查看>>
mysql安装,远程连接,以及修改密码
查看>>
Mybatis查询返回Map类型数据
查看>>
java的深拷贝与浅拷贝
查看>>
程序员如何提高工作效率
查看>>
promise
查看>>
将Java应用部署到SAP云平台neo环境的两种方式
查看>>
数据批量导入Oracle数据库
查看>>
调用lumisoft组件发邮件 不需要身份验证 不需要密码
查看>>
DW 正则
查看>>
抓屏原理
查看>>
UNIX网络编程读书笔记:TCP输出、UDP输出和SCTP输出
查看>>
扩展 DbUtility (1)
查看>>
iOS开发UI篇—使用picker View控件完成一个简单的选餐应用
查看>>
Apple Developer Registration and DUNS Number Not Accepted
查看>>