一、数组(array)是一个有序的数据集合,我们可以通过数组名称(name)和索引(index)进行访问。
【实例1】定义了一个数组emp,数组中的每个元素包含了一个雇员的名字以及其作为索引的员工号。那么emp[1]将会代表1号员工,emp[2]将会代表2号员工,以此类推。
二、JavaScript中没有明确的数组数据类型。但是,我们可以通过使用内置Array对象和它的方法对数组进行操作。
三、数组是一种特殊的对象,适用于存储和管理有序的数据项。

内部

一、数组是一种特殊的对象。使用方括号来访问属性arr[0]实际上是来自于对象的语法。它其实与obj[key]相同,其中arr是对象,而数字用作键(key)。
二、它们扩展了对象,提供了特殊的方法来处理有序的数据集合以及length属性。但从本质上讲,它仍然是一个对象。
【示例1】它是通过引用来复制的:

  1. let fruits = ["Banana"]
  2. let arr = fruits; // 通过引用复制 (两个变量引用的是相同的数组)
  3. alert( arr === fruits ); // true
  4. arr.push("Pear"); // 通过引用修改数组
  5. alert( fruits ); // Banana, Pear — 现在有 2 项了

三、数组真正特殊的是它们的内部实现。JavaScript 引擎尝试把这些元素一个接一个地存储在连续的内存区域,就像插图显示的一样,而且还有一些其它的优化,以使数组运行得非常快。
四、但是,如果我们不像“有序集合”那样使用数组,而是像常规对象那样使用数组,这些就都不生效了。
【示例1】从技术上讲,我们可以这样做:

let fruits = []; // 创建一个数组

fruits[99999] = 5; // 分配索引远大于数组长度的属性

fruits.age = 25; // 创建一个具有任意名称的属性

1、这是可以的,因为数组是基于对象的。我们可以给它们添加任何属性。
2、但是 Javascript 引擎会发现,我们在像使用常规对象一样使用数组,那么针对数组的优化就不再适用了,然后对应的优化就会被关闭,这些优化所带来的优势也就荡然无存了。
五、数组误用的几种方式:

  • 添加一个非数字的属性,比如arr.test = 5。
  • 制造空洞,比如:添加arr[0],然后添加arr1000
  • 以倒序填充数组,比如arr[1000],arr[999]等等。

1、请将数组视为作用于有序数据的特殊结构。它们为此提供了特殊的方法。
2、数组在 JavaScript 引擎内部是经过特殊调整的,使得更好地作用于连续的有序数据,所以请以正确的方式使用数组。
3、如果你需要任意键值,那很有可能实际上你需要的是常规对象{}。

Array对象的属性

属性 描述
length 数组长度
正则表达式操作其他属性

length

一、JavaScript实际上是将元素作为标准的对象属性来存储,把数组索引作为属性名。
二、长度属性是特殊的,它总是返回最后一个元素的索引值加1。
1、JavaScript数组索引是基于0的:他们从0开始,而不是1。这意味着数组长度属性将比最大的索引值大1

var cats = []
cats[30] = ['Dusty']
console.log(cats.length) // 31

三、可以分配length属性 / length属性是可写的。
1、写一个小于数组元素数量的值会缩短数组,该过程是不可逆的。
2、写0会彻底清空数组,这是清空数组最简单的方法。

var cats = ['Dusty', 'Misty', 'Twiggy']
console.log(cats.length) // 3

cats.length = 2
console.log(cats) // ['Dusty', 'Misty']

cats.length = 0
console.log(cats) // []

cats.length = 3
console.log(cats) // [undifind, undefined, undefined]

四、当我们修改数组的时候,length属性会自动更新。准确来说,它实际上不是数组里元素的个数,而是最大的数字索引值加一。
【示例1】一个数组只有一个元素,但是这个元素的索引值很大,那么这个数组的length也会很大:

let fruits = [];
fruits[123] = "Apple";

alert( fruits.length ); // 124

1、要知道的是我们通常不会这样使用数组。

数组的方法(array methods)

【见】数组的方法:https://www.yuque.com/tqpuuk/yrrefz/dzgb6c

创建数组(creating an array):[], new Array(), Array()

创建数组的3种方式

一、创建数组的3种方式:数组字面值 / 数组初始化器 / 括号语法 / 字面值、构造函数法、Array()

数组字面值/数组初始化器 / 括号语法 / 字面值

一、字面值(literal)的方式不仅比其他方式更便捷,同时不易采坑,通常是首选。

var arr = [element0, element1, ..., elementN]

new Array() / 构造函数法

一、语法

var arr = new Array();

var arr = new Array(size); size是具体的数字,表示创建一个size个元素的数组,也就是arr.length = size , var arr = new Array(0); 是清空数组

var arr = new Array(element0, element1, ..., elementN); // 创建新数组并给数组默认值

| 【示例】```javascript var arr = new Array(‘let’, ‘test’) // [‘let’, ‘test’] var arr = new Array(4) // 4指的是长度

 |
| --- |

<a name="bys8Z"></a>
### Array()
```javascript
var arr = Array(element0, element1, ..., elementN)

使用场景

一、创建长度不为0,但是又没有任何元素的数组

var arr = new Array(arrayLength);

var arr = Array(arrayLength);

var arr = [];
arr.length = arrayLength;

1、数组长度(arrayLength)必须为一个数字(Number)。否则,将会创建一个只有单个元素的数组。
2、调用arr.length会返回数组长度,但是数组实际上包含了空的(undefined)元素。因此在数组上使用for…in循环,将不会返回任何的值。
二、用单个元素初始化一个数组,而这个元素恰好又是数字,那么必须使用括号语法。

var arr = [42] // 创建一个只有唯一元素的数组

1、当单个的数字(Number)传递给Array()构造函数时,将会被解释为数组长度,并非单个元素。

var arr = Array(42) // 创建一个没有元素的数组,但是数组的长度被设置成42

// 以上代码等同于
var arr = []
arr.length = 42

(1)new Array(number)创建的数组的所有元素都是undefined

let arr = new Array(2); // 不会创建一个 [2] 的数组。而是创建了一个长度为2,却没有任何项的数组

alert( arr[0] ); // undefined!没有元素。

alert( arr.length ); // length 2

(2)如果N不是一个整数,调用Array(N)将会报RangeError错误

var arr = Array(9.3) // RangeError: Invalid array length

三、如果要创建任意类型的单元素数组,安全的方式是使用字面值。或者在向数组添加单个元素之前先创建一个空的数组。

填充数组(populating an array)

一、可以通过给元素赋值来填充数组

var emp = []
emp[0] = 'Casey Jones'
emp[1] = 'Phil Lesh'
emp[2] = 'August West'

1、如果给数组操作符的是一个非整形数组,那么将作为一个代表数组的对象的属性(property)创建,而非作为数组的元素。

var arr = []
arr[3.4] = 'Oranges'
consoe.log(arr.length) // 0
console.log(arr.hasOwnProperty(3.4)) // true

二、可以在创建数组的时候填充

var myArray = new Array('Hello', myVar, 3.14159)

var myArray = ['Mango', 'Apple', 'Orange']

引用数组元素(referring to array elements)

一、可以使用元素的序号来引用数组的元素

var myArray = ['Wind', 'Rain', 'Fire']
myArray[0] // 引用第一个元素
myArray[1] // 引用第二个元素

1、元素的索引是从0开始的。
二、数组操作符(方括号[])也可以用来访问数组的属性

var arr = ['one', 'two', 'three']
arr[2] // three
arr['length'] // 3

多维数组(multi-dimensional arrays)

一、数组是可以嵌套的,这就意味着一个数组可以作为一个元素被包含在另外一个数组里面
【示例1】存储矩阵

let matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

alert( matrix[1][1] ); // 最中间的那个数

二、创建一个二维数组

var a = new Array(4);
for (i = 0; i < 4; i++) {
  a[i] = new Array(4);
  for (j = 0; j < 4; j++) {
    a[i][j] = "[" + i + "," + j + "]";
  }
}
// [["[0,0]", "[0,1]", "[0,2]", "[0,3]"], ["[1,0]", "[1,1]", "[1,2]", "[1,3]"], ["[2,0]", "[2,1]", "[2,2]", "[2,3]"], ["[3,0]", "[3,1]", "[3,2]", "[3,3]"]]

数组和正则表达式

一、当一个数组作为一个字符串和正则表达式的匹配结果时,该数组将会返回相关匹配信息的属性和元素。
RegExp.exec(),String.match()和String.split()的返回值是一个数组。

数组推导式(Array comprehensions)

一、计划在ECMAScript7被规范化。
二、用来实现如何在另一个数组的基础上构造一个新的数组。
三、推导式可以经常被用在那些需要调用 map() 和 filter()函数的地方,或作为一种结合这两种方式。
【实例1】创建一个数字数组并且创建一个新的数组,数组的每个元素都是原来数值的两倍

var numbers = [1, 2, 3, 4];
var doubled = [for (i of numbers) i * 2];
console.log(doubled); // [2,4,6,8]

1、这与下面的map()方法的操作是等价的

var doubled = numbers.map(function(i){return i * 2;});

【实例2】推导式也可以用来筛选满足条件表达式的元素。下面的推导式用来筛选是2的倍数的元素

var numbers = [1, 2, 3, 21, 22, 30];
var evens = [i for (i of numbers) if (i % 2 === 0)];
console.log(evens); // [2,22,30]

1、filter()也可以达到相同的目的

var evens = numbers.filter(function(i){return i % 2 === 0;});

四、map()和filter()类型的操作可以被组合(等效)为单个数组推导式
【实例1】过滤出偶数,创建一个它的倍数数组的例子

var numbers = [1, 2, 3, 21, 22, 30];
var doubledEvens = [i * 2 for (i of numbers) if (i % 2 === 0)];
console.log(doubledEvens); // logs 4,44,60

1、数组推导式隐含了块作用域。新的变量(如例子中的i)类似于是采用 [let](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let)声明的。这意味着他们不能在推导式以外访问。
五、数组推导式的输入不一定必须是数组; 迭代器、生成器 、字符串也可以用来作为输入;
【实例1】实现filter或者map行为 (参考上面类似数组行为的对象)如下:

var str = 'abcdef';
var consonantsOnlyStr = [c for (c of str) if (!(/[aeiouAEIOU]/).test(c))  ].join(''); // 'bcdf'
var interpolatedZeros = [c+'0' for (c of str) ].join(''); // 'a0b0c0d0e0f0'

1、输入形式是不能保存的,所以我们要使用join()回复到一个字符串。