JavaScript中的数组创建

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

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

  1. 初始化数组并设置初始值

  2. 通过索引访问数组元素

  3. 添加新元素

  4. 删除现有元素

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

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

1. 数组字面量

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

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

在JS Bin中查看

let numbers = [1, 5, 7, 8];
let planets = ['Earth', 'Mercury', 'Jupiter'];

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

在JS Bin中查看

let mixed = [1, 'Earth', null, NaN, undefined, ['Mars']];

1.1 数组字面量中的逗号

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

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

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

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

在JS Bin中查看

let items = ['first', 'second', 'third'];
items; // => ['first', 'second', 'third']

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

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

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

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

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

在JS Bin中查看

let items = ['first', 'second', 'third', ];
items; // => ['first', 'second', 'third']

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

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

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

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

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

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

在JS Bin中查看

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意味着数组在某个索引位置上没有元素(index in array返回false),这与一个值是undefined的元素(index in array返回true)是不同的。

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

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

在JS Bin中查看

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中查看

let source = ['second', 'third'];
let items = ['first', ...source];
items; // => ['first', 'second', 'third']

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

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

在JS Bin中查看

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中查看

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中查看

// 构造器调用
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是通过构造器调用创建的:new Array(1, 5)

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

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

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

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

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

看一个例子:

在JS Bin中查看

let items = new Array(3);
items; // => [<3 empty slots>]
items.length; // => 3

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

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

2.2 枚举元素

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

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

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

let items = new Array('first', 'second', 'third');
items; // => ['first', 'second', 'third']

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

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

在JS Bin中查看

let source = new Array('second', 'third');
let items = new Array('first', ...source);
items; // => ['first', 'second', 'third']

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

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

2.3 有用的静态方法

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

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

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

在JS Bin中查看

let zeros = new Array(5).fill(0);
zeros; // => [0, 0, 0, 0, 0]

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

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

在JS Bin中查看

let zeros = Array.from(new Array(5), () => 0);
zeros; // => [0, 0, 0, 0, 0]

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

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

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

在JS Bin中查看

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中查看

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()new Array(length)的组合。

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

本文转载自:众成翻译

译者:loveky

链接:http://www.zcfy.cc/article/713

原文:http://rainsoft.io/power-up-the-array-creation-in-javascript/

JavaScript中的数组创建的更多相关文章

  1. 前端开发:Javascript中的数组,常用方法解析

    前端开发:Javascript中的数组,常用方法解析 前言 Array是Javascript构成的一个重要的部分,它可以用来存储字符串.对象.函数.Number,它是非常强大的.因此深入了解Array ...

  2. javascript中的数组扩展(一)

     javascript中的数组扩展(一) 随着学习的深入,发现需要学习的关于数组的内容也越来越多,后面将会慢慢归纳,有的是对前面的强化,有些则是关于前面的补充. 一.数组的本质    数组是按照次序排 ...

  3. JavaScript中的数组详解

    JavaScript中的数组 一.数组的定义 数组是值的有序集合,或者说数组都是数据的有序列表. 二.创建数组 [字面量形式] 1.空数组 var arr=[]; 2.带有元素的数组 var arr= ...

  4. JavaScript中对数组和数组API的认识

    JavaScript中对数组和数组API的认识 一.数组概念: 数组是JavaScript中的一类特殊的对象,用一对中括号“[]”表示,用来在单个的变量中存储多个值.在数组中,每个值都有一个对应的不重 ...

  5. JavaScript中的数组和字符串

    知识内容: 1.JavaScript中的数组 2.JavaScript中的字符串 一.JavaScript中的数组 1.JavaScript中的数组是什么 数组指的是数据的有序列表,每种语言基本上都有 ...

  6. javascript中稀疏数组和密集数组

    密集数组 数组是一片连续的存储空间,有着固定的长度.加入数组其实位置是address,长度为n,那么占用的存储空间是address[0],address[1],address[2].......add ...

  7. Javascript中判断数组的正确姿势

    在 Javascript 中,如何判断一个变量是否是数组? 最好的方式是用 ES5 提供的 Array.isArray() 方法(毕竟原生的才是最屌的): var a = [0, 1, 2]; con ...

  8. JavaScript中对数组的操作

    原文:JavaScript中对数组的操作 一:数组的使用 1.定义:JavaScript中对数组的定义有两种形式.如: .var arr = [12,3,5,8]; .var arr = new Ar ...

  9. JavaScript中一个对象数组按照另一个数组排序

    JavaScript中一个对象数组按照另一个数组排序 需求:排序 const arr1 = [33, 11, 55, 22, 66]; const arr2 = [{age: 55}, {age: 2 ...

随机推荐

  1. C# ref 和 out 的使用

    private void button1_Click(object sender, EventArgs e) { ; ; Fun(ref a,ref b); //把a的地址和b的地址 传递过去 Mes ...

  2. EF6 mysql配置

    如何把一个ef项目 从sqlserver改为mysql 首先在引入了ef的层再引入这两个包,注意两个的版本一定要一样,一定要一样,一定要一样,不然就会报错 MySql.Data.Entity目前的最新 ...

  3. eas之设置编辑界面分录的某一列不可编辑

    KDTEntrys.getColumn(“xx”).getStayAttributes().setlokced(true);

  4. 多态(day10)

    二十二 多态(Polymorphic) 函数重写(虚函数覆盖).多态概念 如果将基类中的某个成员函数声明为虚函数,那么子类与其具有相同原型的成员函数就也将是虚函数,并且对基类中的版本形成覆盖. 这时, ...

  5. CF135E Weak Subsequence (计数问题)

    题目传送门 题目大意:对于给定字符集大小k,求有多少个字符串满足它的最长[既是子串又是弱子序列]的长度为w: 神仙计数题 打表发现,对于字符串S而言,它的最长[既是子串又是弱子序列],一定存在一个对应 ...

  6. CSS学习笔记之CSS3新特性

    目录 1.边框 2.背景 3.文本 4.字体 5.转换 6.过渡 7.动画 8.多列 9.自定义尺寸 CSS 用于控制网页的样式和布局,而 CSS3 是最新的 CSS 标准,这篇文章将着重介绍 CSS ...

  7. ZOJ 2699 Police Cities

    Police Cities Time Limit: 10 Seconds      Memory Limit: 32768 KB Once upon the time there lived a ki ...

  8. mybatis源码阅读-Transaction和TransactionFactory(四)

    Transaction 类图 接口定义 public interface Transaction { Connection getConnection() throws SQLException; v ...

  9. 【ACM】hdu_zs3_1005_String Matching_201308100920

    String Matching Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 20000/10000K (Java/Other)Tota ...

  10. 5.2 calendar--通用日期的相关函数(4)

    calendar类提供以下的函数来推断日历相关的内容: calendar.setfirstweekday(weekday) 设置一周里那一天作为第一天.0是表示星期一,6是表示星期天. 样例: #py ...