前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript中的数组创建

JavaScript中的数组创建

作者头像
疯狂的技术宅
发布2019-03-27 15:08:14
3.4K0
发布2019-03-27 15:08:14
举报
文章被收录于专栏:京程一灯京程一灯

数组是一个包含了对象或原始类型的有序集合。很难想象一个不使用数组的程序会是什么样。

以下是几种操作数组的方式:

  1. 初始化数组并设置初始值
  2. 通过索引访问数组元素
  3. 添加新元素
  4. 删除现有元素

本文涵盖了数组的初始化以及设置初始值的操作。在JavaScript中要做到这一点的基本方法是使用数组字面量,例如 [1,5,8]或是数组构造器 newArray(1,5,8)

除了手动枚举之外,JavaScript还提供了更有趣更直接的数组创建方式。让我一起看看在JavaScript中初始化数组的一般场景和高级场景吧。

1. 数组字面量

数组字面量由一组包裹在方括号 [ ]之间的逗号分隔的元素 element1,element2,...,elementN组成。

让我们看几个数组字面量的例子:

在JS Bin中查看

代码语言:javascript
复制
let numbers = [1, 5, 7, 8];
let planets = ['Earth', 'Mercury', 'Jupiter'];

数组字面量可以包含任意类型的元素,包括 null, undefined, 原始类型以及对象:

在JS Bin中查看

代码语言:javascript
复制
let mixed = [1, 'Earth', null, NaN, undefined, ['Mars']];

1.1 数组字面量中的逗号

逗号 ,用来分隔数组字面量中的元素。基于逗号的位置或是逗号之间元素的缺失的情况,不同结构的数组会被创建。

让我们详细看一看现有的三种情况。

第一种情况:普通的数组字面量

通常情况是在任何一对逗号之间都有一个元素并且数组字面量不以逗号开始或结尾。这是推荐的使用逗号分隔手动初始化数组的方式:

在JS Bin中查看

代码语言:javascript
复制
let items = ['first', 'second', 'third'];
items; // => ['first', 'second', 'third']

items是由2个逗号分隔的3个元素创建的。

在这个例子中 item是一个密集数组,因为它的元素有着连续的索引(或者简单来说数组中没有空洞)。

大多数时候,你会使用这种方式初始化数组。

第二种情况: 在数组末尾的一个无用逗号

第二种情况和第一种情况类似,只不过在最后一个逗号之后没有指定元素。这种情况中,最后一个逗号会被JavaScript忽略:

在JS Bin中查看

代码语言:javascript
复制
let items = ['first', 'second', 'third', ];
items; // => ['first', 'second', 'third']

在元素 'third'之后指定的一个逗号,它是数组中的最后一个逗号并且在那之后没有任何元素。这个末尾的逗号是无用的,意味着它对新创建的数组没有任何影响。

这种情况下JavaScript也会创建一个密集数组。

第三种情况: 逗号之间没有元素

第三种情况发生在当一对逗号之间没有指定元素或是数组字面量以一个逗号开始时。

这会创建一个稀疏数组:一个其元素索引不连续的集合(换句话说数组中存在空洞)。

下面的数组字面量以逗号开始,创建了一个稀疏数组:

在JS Bin中查看

代码语言:javascript
复制
let items = [, 'first', 'second', 'third'];
items;        // => [<1 empty slot>, 'first', 'second', 'third']
items[0];     // => undefined
items[1];     // => 'first'
items.length; // => 4

数组字面量 [,...]以逗号开始。结果是 items是一个稀疏数组,在索引 0的位置是一个空slot。访问空slot items[0]会得到 undefined

区分一个空slot和一个值是 undefined的元素是很重要的。通过索引访问这种类型的元素时都会得到 undefined,这使得区分它们变得很棘手。

空slot意味着数组在某个索引位置上没有元素( indexinarray返回 false),这与一个值是 undefined的元素( indexinarray返回 true)是不同的。

需要注意的是空slot在Firefox的控制台会被显示为 <1 empty slot>,这是展示空slot的正确方法。Chrome的控制台会展示 undefinedx1。其它浏览器的控制台只会简单的展示 undefined

当数组字面量的两个逗号之间没有元素时也会创建一个稀疏数组:

在JS Bin中查看

代码语言:javascript
复制
let items = ['first', , 'second', 'third'];
items;        // => ['first', <1 empty slot> ,'second', 'third']
items[0];     // => 'first'
items[1];     // => undefined
items.length; // => 4

数组字面量包含了中间没有元素的逗号: [...,,...]。这样 item成了一个索引 1处是一个空slot的稀疏数组。访问空slot items[1]会得到 undefined

通常你应该避免这种会创建稀疏数组的使用方式。同时你也应该尽可能的不去操作稀疏数组。

在一个数组字面量中删除或是添加元素时你可能会在不经意间创建一个稀疏数组。因此在修改之后切记仔细检查。

1.2 spread运算符带来的改善

ECMAScript 6中引入的spread运算符改善了使用其它数组中的元素初始新数组这一操作。

在很多场景下spread运算符都可以使数组创建变得更简单。方法就是在数组字面量中把 ...作为源数组的前缀,然后源数组中的元素就被包括到新创建的数组中了。就这么简单。

下面的数组字面量在创建时使用了spread运算符:

在JS Bin中查看

代码语言:javascript
复制
let source = ['second', 'third'];
let items = ['first', ...source];
items; // => ['first', 'second', 'third']

数组字面量 ['First',...source]表示 'First'会被作为数组中的第一个元素。剩余的元素则是通过spread运算符从 source数组取得。

常规的元素枚举方式可以和spread运算符可以不受限制的组合在一起。

在JS Bin中查看

代码语言:javascript
复制
let odds = [1, 3, 5];
let evens = [4, 6];
let zero = 0;
let negative = -1;
let items = [...odds, zero, ...evens, negative];
items; // => [1, 3, 5, 0, 4, 6, -1]

创建 items时使用一个组合了普通变量 zeronegative以及前置spread运算符的源数组 ...odds...evens的集合。

由于spread运算符接收的是普通的可迭代对象(数组默认就是可迭代的),这使得自定义的初始化成为可能。

一个生成器函数也会返回一个可迭代的生成器对象,因此你可以利用生成器的灵活性来创建数组。

让我们创建一个第一个参数代表元素值第二个参数代表元素数量的生成器函数。然后使用它和spread运算符以及数组字面量来初始化新数组:

在JS Bin中查看

代码语言:javascript
复制
function* elements(element, length) {
  let index = 0;
  while (length > index++) {
    yield element;
  }
}
[...elements(0, 5)];    // => [0, 0, 0, 0, 0]
[...elements('hi', 2)]; // => ['hi', 'hi']

每次执行 elements(element,length)时都会创建一个生成器对象。spread运算符会利用该生成器对象来初始化数组。

[...elements(0,5)]会创建一个有5个0的数组。而 [...elements('hi',2)]会创建一个有两个字符串 'h1'的数组。

2. 数组构造器

JavaScript中的数组是一个对象。和任何对象一样,它有一个可以用来创建新实例的构造器函数 Array。让我们看一个例子:

在JS Bin中查看

代码语言:javascript
复制
// 构造器调用
let arrayConstr = new Array(1, 5);
arrayConstr;                        // => [1, 5]
typeof arrayConstr;                 // => 'object'
arrayConstr.constructor === Array;  // => true
// 数组字面量
let arrayLiteral = [1, 5];
arrayLiteral;                       // => [1, 5]
typeof arrayLiteral;                // => 'object'
arrayLiteral.constructor === Array; // => true

arrayConstrarrayLiteral都是数组实例,它们的构造器都是 Array。对象 arrayConstr是通过构造器调用创建的: newArray(1,5)

你也可以像调用普通函数那样通过Array来创建数组实例: Array(1,5)

你应该更倾向于使用字面量 [item1,item2,...,itemN]而不是构造器 newArray(item1,item2,...,itemN)来创建数组。主要原因是数组字面量的写法更短,更简单。还有一个原因就是数组构造器在第一个参数是不同类型的值时,产生的怪异行为。

让我们看看 Array使如何根据第一个参数的类型以及参数的个数来创建数组实例的吧。

2.1 数值类型的参数下创建稀疏数组

当数组构造器 newArray(numberArg)以一个单一的数值类型的参数调用时,JavaScript会创建一个带有参数指定的个数的空slot的稀疏数组。

看一个例子:

在JS Bin中查看

代码语言:javascript
复制
let items = new Array(3);
items;        // => [<3 empty slots>]
items.length; // => 3

newArray(3)是一个带有单一参数 3的构造器调用。一个长度为 3的稀疏数组 items被创建了,但实际上它并不包含任何元素而只是有几个空slot。

这种创建数组的方式本身并没有什么价值。然而把它和一些静态方法组合起来用于创建指定长度的数组并填充生成的元素时却是有用的。

2.2 枚举元素

如果调用 Array构造器时传入了一个参数列表而不是单个数字,那么这些参数就会成为数组的元素。

这种方式和数组字面量的方式几乎一样,只不过是在一个构造器调用中而已。

下面的例子创建了一个数组:

代码语言:javascript
复制
let items = new Array('first', 'second', 'third');
items; // => ['first', 'second', 'third']

newArray('first','second','third')使用参数中的元素创建了一个数组。

由于spread运算符的灵活性,在构造器调用中使用来自其它数组的元素也是可行的:

在JS Bin中查看

代码语言:javascript
复制
let source = new Array('second', 'third');
let items = new Array('first', ...source);
items; // => ['first', 'second', 'third']

newArray('First',...source)创建数组时使用了 'First'元素以及 source数组中的所有元素。

无论哪种方式,你都应该倾向于使用数组字面量,因为它更简单直接。

2.3 有用的静态方法

当读到关于通过在构造器调用中传入一个数字来创建稀疏数组的部分时你可能好奇这有什么实际的用处。

ECMAScript 6增加了一些有用的方法如 Array.prototype.fill()Array.from()。这两个方法都可以用来填充一个稀疏数组中的空slot。

让我使用 fill()方法来创建一个包含5个0的数组:

在JS Bin中查看

代码语言:javascript
复制
let zeros = new Array(5).fill(0);
zeros; // => [0, 0, 0, 0, 0]

newArray(5)创建了一个有5个空slot的稀疏数组。接着 fill(0)方法用 0填充了空slot。

静态方法 Array.from()则有着更宽的使用场景。像上边的例子一样,让我们创建一个包含5个0的数组:

在JS Bin中查看

代码语言:javascript
复制
let zeros = Array.from(new Array(5), () => 0);
zeros; // => [0, 0, 0, 0, 0]

一个通过 newArray(5)创建的长度为 5的稀疏组数作为参数被传递给 Array.from()。第二个参数作为一个返回 0的映射函数。

共执行了 5次迭代,每次迭代中箭头函数的返回值被用作数组的元素。

由于在每次迭代中都会执行映射函数,因此动态创建数组元素是可行的。让我们创建一个包含 15的数组:

在JS Bin中查看

代码语言:javascript
复制
let items = Array.from(new Array(5), (item, index) => index + 1);
items; // => [1, 2, 3, 4, 5]

映射函数被调用时会传入两个参数:当前的 item以及当前迭代的 index。索引参数被用来生成元素: index+1

Array.from()的第一个参数可以接受任何可迭代对象,这使得它更有价值。

让我们使用一个生成器对象创建一个递增的数字列表:

在JS Bin中查看

代码语言:javascript
复制
function* generate(max) {
  let count = 0;
  while (max > count++) {
    yield count;
  }
}
let items = Array.from(generate(5));
items;       // => [1, 2, 3, 4, 5]
let itemsSpread = [...generate(5)];
itemsSpread; // => [1, 2, 3, 4, 5]

generate(max)是一个生成器函数,它会生成从一串从 1max的数字。

Array.from(generate(5))使用一个生成器对象作为参数创建了一个包含 15数字的数组。

使用spread运算符 [...generate(5)]和数组字面量可以达到同样的目的。

3. 总结

数组初始化是操作集合时的常见操作。JavaScript提供了多种方法以及灵活性来实现该目的。

数组构造器的行为在很多情况下会让你感到意外。因此数组字面量是初始化数组实例更好,更简单的方式。

当数组需要根据基于每个迭代元素的计算进行初始化时, Array.from()是一个不错的选择。

如果数组元素需要被填充为同一个值,使用 Array.prototype.fill()newArray(length)的组合。

不要低估可迭代对象和生成器函数的能力,它们可以和spread运算符组合起来使用在数组字面量或是 Array.from()中。


往期精选文章

使用虚拟dom和JavaScript构建完全响应式的UI框架

扩展 Vue 组件

使用Three.js制作酷炫无比的无穷隧道特效

一个治愈JavaScript疲劳的学习计划

全栈工程师技能大全

WEB前端性能优化常见方法

一小时内搭建一个全栈Web应用框架

干货:CSS 专业技巧

四步实现React页面过渡动画效果

让你分分钟理解 JavaScript 闭包



小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-10-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京程一灯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 数组字面量
    • 1.1 数组字面量中的逗号
      • 第一种情况:普通的数组字面量
      • 第二种情况: 在数组末尾的一个无用逗号
      • 第三种情况: 逗号之间没有元素
    • 1.2 spread运算符带来的改善
    • 2. 数组构造器
      • 2.1 数值类型的参数下创建稀疏数组
        • 2.2 枚举元素
          • 2.3 有用的静态方法
          • 3. 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档