[TOC]
# 数组
## **概念**
  将多个元素(通常是同一类型)按一定顺序排列放到一个集合中,那么这个集合就叫称之为做数组。
<br>
## **创建数组**
  创建数组也叫**定义数组**,定义一个数组变量跟定义一个基本类型的变量格式几乎一样。
  定义数组语法格式:
>[success]var 数组变量名 = 数组变量值;
var 数组变量名 = [元素1,元素2,元素3……];
元素与元素之间用英文逗号“ , ”隔开。
```
//变量
// 创建一个空数组
var arr = [];
// 创建一个数组,用于存储3个年龄,年龄分别为 20,30,40;
var ageArray = [20,30,40];
console.log(ageArray);
// 创建一个数组,用于存储你喜欢的三个明星的姓名
var nameArray = ['热巴', 'baby', '柳岩'];
console.log(nameArray);
// 创建一个数据,用于存储50个学生的姓名
var names = ['zs', 'ls', 'ww', 'zl'];
console.log(names);
//字面量
[];
[20,30,40];
['热巴', 'baby', '柳岩'];
```
## **获取数组元素**
  我们可以根据数组的下标(又叫索引)获取数组中某个元素。数组元素下标从0开始,如果使用一个不存在的下标获取数组元素,将会获取到一个undefined值。
语法格式:格式:数组名\[ 索引 \]  **索引**又称作**下标**
```
// 功能:获取数组对应下标的那个值,如果下标不存在,则返回undefined。
var nameArray = ['热巴', 'baby', '柳岩'];
nameArray[0]; // 热巴
nameArray[2]; // 柳岩
nameArray[3]; // 这个数组的最大下标为2,因此此处返回undefined
console.log(nameArray);
```
<br>
## **数组的存储的特点**
  我们可以在数组中存储不同类型的元素,但是这样的数组不方便我们处理数据,所以不推荐使用。我们还可以获取数组的长度,获取数组的最后一项,动态改变数组等等。
1. JavaScript数组元素的类型可以不一致(不推荐使用)
```
var arr = ['热巴', 'baby', 18, 19 ];
console.log(arr);
```
2. 使用length属性获取数组的长度
```
var names = ['热巴', 'baby', '柳岩'];
console.log(names.length);
```
3. 获取数组的最后一项
```
var names = ['热巴', 'baby', '柳岩'];
console.log(names[names.length-1]);
```
4. 动态改变(修改或添加元素)数组长度
>[success]格式:数组名[下标/索引] = 值;
  如果下标有对应的值,会把原来的值覆盖,如果下标不存在,会给数组新增一个元素。
```
var names = ['热巴', 'baby', '柳岩'];
// 把'热巴'替换成了'幂幂'
arr[0] = '幂幂';
// 给数组新增加了一个'圆圆'的值
arr[3] = '圆圆';
//从数组的最后一项的下一个位置开始加入新元素
for (var i = 0; i < 5; i++) {
names[names.length] = i+'';
}
console.log(names);
```
<br>
## **遍历数组**
遍历:遍及所有,历经全部的意思。对数组的每一个元素都访问一次就叫遍历数组。
<br>
### **使用for循环遍历数组**
  我们发现,数组索引和for循环次数都是从0开始,所以我们可以把for循环中的循环次数 i 当做数组的索引 index 来使用,这样就可以访问到数组的每一个元素了。
1. 固定格式
```
for(var i = 0; i < arr.length; i++) {
// 数组遍历的固定结构
}
```
2. 获取数组中的多个元素,遍历(遍布所有,历经全部)数组
```
//获取数组中的多个元素,遍历(遍布所有,历经全部)数组
var array = [];
//动态天10个数组元素
for (var i = 0; i < 10; i++) {
array[i] = '我是第' + i + '个元素';
}
console.log(array);
```
3. 正向遍历数组
```
//1.正向遍历数组,访问数组的每一个元素
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
```
4. 逆向遍历数组
```
//2.逆向遍历数组
for (var i = array.length - 1; i >= 0; i--) {
console.log(array[i]);
}
```
## **案例**
### 求一组数的和与平均值
需求:
  1、定义一个具有5个数值元素的数组,求这个数组中所有元素的和与平均值
  思路:遍历数组将数组元素累加到sum变量中,然后使用sum除以数组的长度求得平均值。
```
//定义一个数组
var numbers = [2, 3, 5, 2, 8];
var sum = 0;
var avg = 0;
//遍历数组
for (var i = 0; i < numbers.length; i++) {
sum = sum + numbers[i];
}
console.log('所有数的和:'+sum);
console.log('平均值:'+sum/numbers.length);
```
<br>
### 求一组数中的最大值
需求:
  2、求一组数 \[6, 13, 8, 21, 14, 5\] 中的最大值
  需求分析:
(1)定义一个变量max,用于存储最大值(为了方便处理,我们可以将max初始化值为数组的第一个元素)
(2)用max跟数组的每一个元素比较大小,如果max值小于元素值,则用数组元素值覆盖掉max值,最后得到的max就是整个数组中最大的值。
```
// 定义一个数组,用于存储一组数值
var arrayNum = [6, 13, 88, 21, 14, 5];
// 定义一个变量,用于存储求出的最大值
var max = arrayNum[0];
// 遍历数组,比较元素的与max的大小
for (var i = 1; i < arrayNum.length; i++) {
//比较当前遍历到的元素与max的值的大小,把大的值赋值给max
var num = arrayNum[i];
if (max < num) {
//将较大的值赋值给max
max = num;
}
}
console.log(max);// 88
```
### 求一组数中的最大最小值及其所在的位置
需求:
  4、求一组数 \[6, 13, 8, 2, 21, 134, 5\] 中的最大最小值及其所在的位置
  需求分析:
(1)在求得最大值的同时,将最大值的索引存储起来,遍历结束后即可得到最大值及其下标
(2)同理可求最小下标
```
//求一组数中的最大值和最小值,以及所在位置
//最大最小值,位置
var numbers = [6, 13, 8, 2, 21, 134, 5];
//假设最大最小值
var max = numbers[0];
var min = numbers[0];
//同时记录最大最小值下标(位置)
var maxIndex = 0;
var minIndex = 0;
for (var i = 1; i <= numbers.length; i++) {
if (max < numbers[i]) {
max = numbers[i];
maxIndex = i;
}
if (min > numbers[i]) {
min = numbers[i];
minIndex = i;
}
}
console.log('最小值:'+min, minIndex);
console.log('最大值:'+max, maxIndex);
```
<br>
### **分隔数组(重要)**
需求:
  5、将字符串数组 \['孙悟空', '比克大魔王', '天津饭', '克林', '布尔玛'\] 的元素用 | 分割成一个字符串,比如
  ' 孙悟 | 比克大魔王 | 天津饭 | 克林 | 布尔玛 '.
  需求分析:
(1)遍历数组,在数组每一个元素面后拼接 |
需求注意的问题:
1、代码中的分隔符 | 不能写死
2、最后一个元素后面不能有分隔符
```
//将字符串数组用|或其他符号分割成一个字符串
var names = ['孙悟空', '比克大魔王', '天津饭', '克林', '布尔玛'];
var str = '';
for (var i = 0; i < names.length; i++) {
//names[i] = names[i] + separator;
str += names[i] + '|';
}
console.log(names);
console.log(str);
```
```
//解决两个小问题:(1)分隔符写死的问题;(2)最后一项有多余分隔符的问题
var names = ['孙悟空', '比克大魔王', '天津饭', '克林', '布尔玛'];
var separator = '|';
var str = names[0];
for (var i = 1; i < names.length; i++) {
//names[i] = names[i] + separator;
str += separator + names[i];
}
console.log(names);
console.log(str);
```
<br>
### **替换数组中指定的元素(重要)**
需求:
  6、将数组 \[6, 13, 0, 8, 2, 0, 21, 14, 0, 5\] 中的元素为 0 的项去掉,即将不为0的值存入一个新的数组,将新数组输出到浏览器控制台
  需求分析:
(1)遍历数组,获取到所有非0元素
(2)将非0元素存储到新数组中,输出
  注意:
  将非0数据存储到新数组的时候,每个元素在存储到新数组时的位置,应该是新数组的最后一个元素的下一个位置。
```
// 定义一个数组
var array = [6, 13, 0, 8, 2, 0, 21, 14, 0, 5];
// 定义一个新的数组,用于存储不为0的元素
var newArray = [];
// 遍历array数组,将数组中不为0的元素存储到newArray中
for (var i = 0; i < array.length; i++) {
// 判断当前遍历到的元素是否是为0
if (array[i]!==0) {
// 将array数组中的元素存储到newArray中
// newArray[i] = array[i];// 问题:导致newArray中元素的索引不连续
// 将array中非0元素添加到newArray中的最后一个元素的下一个位置中
newArray[newArray.length] = array[i];
}
}
console.log(array);
console.log(newArray);
```
<br>
### **翻转数组(重要)**
需求:
  7、将数组 \['孙悟空', '琪琪', '克林', '龟仙人'\] 翻转,得到新数组 \["龟仙人", "克林", "琪琪", "孙悟空"\]
  需求分析:
(1)逆向遍历数组,将数组的元素存储到新数组中
  注意:
  元素存储到新数组时的下标处理(参考上一题 “替换指定的元素”)。
```
// 翻转数组
var names = ['孙悟空', '琪琪', '克林', '龟仙人'];
var reverse = [];
for (var i = names.length-1; i >=0; i--) {
reverse[reverse.length] = names[i];
}
console.log(reverse);
```
### **冒泡排序(重要)**
需求:
  8、将一组数\[9, 6, 7, 1, 5, 2\] 从小到大排序
  需求分析:
  (1)如下图第一趟,将数组元素前一个与后一个比较大小,如果前一个大于后一个,则交换这两个元素的位置。这一趟做了5次比较,即 “ 数组长度-1 ”次比较。
  (2)如下图第二趟,将数组元素前一个与后一个比较大小,如果前一个大于后一个,则交换这两个元素的位置。这一趟做了4次比较,即 “ 数组长度-2 ”次比较。
  (3)以此类推,第N趟时,做 “ 数组长度-N ” 次比较。
![](images/冒泡排序04.png)
  注意,在循环过程中,比较次数会随着比较趟数的增加而减少,在代码中, i 和 j 会形成这样的关系:
  j < arr.length - i , 如下代码:
```
//冒泡排序,从小到大的排序
var arr = [9, 6, 7, 1, 5, 2];
//外层循环:控制比较的趟数
for (var i = 1; i <= arr.length - 1; i++) {
//内层循环:控制每一趟的比较次数,判断元素大小,交换元素位置
for (var j = 1; j <= arr.length - i; j++) {
//判断元素大小
if (arr[j-1] > arr[j]) {
//交换元素位置
var temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
}
}
}
console.log(arr);
```
  6个元素的一组数可能只需要比较一趟就已经排好序了。但如果使用上述代码,不管有没有排好序,都会执行arr.length - 1趟,每一趟会执行arr.length - 1 - i此比较,这样的循环不合理!我们可以对以上的冒泡排序代码进行优化。
  优化思路:如果这组数没有排好序,那么就一定会进行数据交换,我们创建一个变量来记录每一趟中是否交换过数据,然后根据这个变量判断这一趟是否已经排好序。
```
//优化:解决已经排序好但还继续循环比较的问题
var arr = [86, 57, 61, 18, 40, 34];
var conut = 0;
//外层循环:控制比较的趟数
for (var i = 0; i < arr.length - 1; i++) {
//假设已经排序完成
var isOver = true;
//内层循环:控制每一趟的比较次数,判断元素大小,交换元素位置
for (var j = 0; j < arr.length - 1 - i; j++) {
//判断元素大小
if (arr[j] > arr[j + 1]) {
//还未排序完成
isOver = false;
//交换元素位置
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
if (isOver) {
break;
}
}
console.log(arr);
console.log(conut);
```