手把手5分钟入门JavaScript数组,万字文超详细手绘操作执行过程②JavaScript数据结构与算法系列
Posted 狼丶宇先生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手5分钟入门JavaScript数组,万字文超详细手绘操作执行过程②JavaScript数据结构与算法系列相关的知识,希望对你有一定的参考价值。
千万别觉得javascript的数组就是一个[]中括号,虽然常用,可能你觉得也简单,但是真的要深入,真的还是有点难度的。
一、数组的简介
几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构。JavaScript里也有数组类型,尽管它的第一个版本并没有支持数组。本章将深入学习数组数据结构和它的能力。
数组存储一系列同一种数据类型的值。虽然在JavaScript里,也可以在数组中保存不同类型的值,但我们还是遵守最佳实践,避免这么做(大多数语言都没这个能力)。
- 为什么使用数组?
假如有这样一个需求:保存所在城市每个月的平均温度。可以这么做:
const m1 = 31.1;
const m2 = 34.2;
const m3 = 28.8;
const m4 = 32.2;
const m5 = 30.1;
const m6 = 19.9;
当然,这肯定不是最好的方案。按照这种方式,如果只存一年的数据,我们能管理12个变量。
若要多存几年的平均温度呢?幸运的是,我们可以用数组来解决,更加简洁地呈现同样的信息。
const ms = [];
ms[0] = 31.1;
ms[1] = 34.2;
ms[2] = 28.8;
ms[3] = 32.2;
ms[4] = 30.1;
ms[5] = 19.9;
这个时候数组ms里的内容就如下图所示了:
二、JavaScript的数组
- 创建和初始化数组
用JavaScript声明、创建和初始化数组很简单,就像下面这样。
let arr = new Array(); //方法1
arr = new Array(7); //方法2
arr = new Array('a','b','c','d'); //方法3
arr = ['a','b','c','d']; //方法4
- 使用new关键字,就能简单地声明并初始化一个数组(方法1)
- 用这种方式,还可以创建一个指定长度的数组(方法2)
- 另外,我们也可以直接将数组元素作为参数传递给它的构造器(方法3)
- 最后也可以简单粗暴的使用中括号[] (方法4)
简单粗暴灵活,推荐方法为第四种,不推荐使用new Array创建。
- 访问元素和迭代数组
要访问数组里特定位置的元素,可以用中括号传递数值位置,得到想知道的值或者赋新的值。假如我们想输出数组daysofweek里的所有元素,可以通过循环选代数组、打印元素,如下所示。
for (let i = 0; 1 < arr.length; i++){
console.log(arr[i]);
}
- 添加元素
在数组中添加和删除元素也很容易,但是有时候也会很棘手。假如我们有这样的一个数组 numbers,初始化成了 0 到 9 。
let numbers = [0,1,2,3,4,5,6,7,8,9];
在数组末尾插入一个元素
如果想要给数组添加一个元素,例如添加一个10,只要把值赋值给数组中最后一个空位上的元素即可。
numbers[numbers.length] = 10;
需要注意的是:
在JavaScript中,数组是一个可以修改的对象。如果添加元素,它就会动态增长。在C和Java等其他语言里,我们要决定数组的大小,想添加元素就要创建一个全新的数组,不能简单地往其中添加所需的元素。
使用push方法
另外,还有一个push方法,能把元素添加到数组的末尾。通过push方法,我们能添加任意个元素。
numbers.push(11);
numbers.push(12,13);
console.log(numbers);
在数组的开头插入元素
现在,我们希望在数组中插入一个新元素(数-1),不像之前那样插人到最后,而是放到数组的开头。为了实现这个需求,首先要腾出数组里第一个元素的位置,把所有的元素向右移动一位。
我们可以循环数组中的元素,从最后一位(长度值就是数组的末尾位置)开始,将对应的前一个元素(i-1)的值赋给它(i),依次处理,最后把我们想要的值赋给第一个位置(索引0)上。我们可以将这段逻辑写成一个函数,甚至将该方法直接添加在Array的原型上,使所有数组的实例都可以访问到该方法。
下面的代码表现了这段逻辑。
Array.prototype.insertFirstPosition = function(value){
for(let i = this.length; i >=0; i++){
this[i] = this[i - 1];
}
this[0] = value;
}
numbers.insertFirstPosition(-1);
下图描述一下操作过程:
使用unshift方法
在JavaScripr里,数组有一个方法叫 unshift,可以直接把数值插入数组的开头(此方法背后的逻辑和insertFirstPosition方法的行为是一样的)。
numbers.unshift(-2);
numbers.unshift(-4,-3);
那么,用unshift方法,我们就可以在数组的开始处添加值-2,然后添加-3、-4等。这样数组就会输出数-4到13。
- 删除元素
目前为止,我们已经学习了如何给数组的开始和结尾位置添加元素。下面来看一下怎样从数组中删除元素。
从数组末尾删除元素
要删除数组里最靠后的元素,可以用pop方法。
numbers.pop();
小技巧:
通过push和pop方法,就能用数组来模拟栈。剧透:你将在下一章看到这部分内容(栈结构)。
现在,数组输出的数是-4到12,数组的长度是17。
从数组开头删除元素
如果要移除数组里的第一个元素,可以用下面的代码。
for(let i = 0; i < numbers.length; i++){
numbers[i] = numbers[i + 1];
}
下图呈现了这段代码的执行过程。
我们把数组里所有的元素都左移了一位,但数组的长度依然是17,这意味着数组中有额外的一个元素(值是 undefined)。
在最后一次循环里,i+1引用了数组里还未初始化的一个位置。
在Java、C/C+或C#等一些语言里,这样写可能会抛出异常,因此不得不在nunbers.length-1处停止循环。
可以看到,我们只是把数组第一位的值用第二位覆盖了,并没有删除元素(因为数组的长度和之前还是一样的,并且多了一个未定义元素)。
要从数组中移除这个值,还可以创建一个包含刚才所讨论逻辑的方法,叫作removeFirstPosition。但是,要真正从数组中移除这个元素,我们需要创建一个新的数组,将所有不是undefined 的值从原来的数组复制到新的数组中,并且将这个新的数组赋值给我们的数组。
要完成这项工作,也可以像下面这样创建一个reIndex方法。
Array.prototype.reIndex = function(array){
const newArr = [];
for(let i = 0; i < array.length; i++){
if(array[i] !== undefined){
newArr.push(array[i]);
}
}
return newArr;
}
// 手动移除第一个元素并排序
Array.prototype.removeFirstPosition = function(){
const newArr = [];
for(let i = 0; i < this.length; i++){
this[i] = this[i + 1]
}
return this.reIndex(this);
}
numbers = numbers.removeFirstPosition();
注意:
上面的代码只应该用作示范,不应该在真实项目中使用。要从数组开头删除元素,我们应该始终使用shift方法,这将在下一节中展示。
使用shift方法
要删除数组的第一个元素,可以用shift方法实现。
numbers.shift();
假如本来数组中的值是从-4到12,长度为17。执行了上述代码后,数组就只有-3到12了也会减小到16。
通过shift和unshift方法,就能用数组模拟基本的队列数据结构,后面会讲到。
- 任意位置添加或删除元素
目前为止,我们已经学习了如何添加元素到数组的开头或末尾,以及怎样删除数组开头和结尾位置上的元素。那么如何在数组中的任意位置上删除或添加元素呢?
我们可以使用splice方法,简单地通过指定位置/索引,就可以删除相应位置上指定数量3的元素。
numbers.splice(5,3);
这行代码删除了从数组索引5开始的3个元素。这就意味着numbers[5]、numbers[6]和numbers[7]从数组中删除了。现在数组里的值变成了-3、-2、-1、0、1、5、6、7、8、9、10、11和12(2、3、4已经被移除)。
对于JavaScript 数组和对象,我们还可以用delete 运算符删除数组中的元素,例如 delete numbers [0]。然而,数组位置0的值会变成 undefined,也就是说,以上操作等同于numbers[0] = undefined。因此,我们应该始终使用splice、pop或 shift方法来删除数组元素。
现在,我们想把数2、3、4插人数组里,放到之前删除元素的位置上,可以再次使用splice方法。
numbers,splice(5,0,2,3,4);
splice方法接收的第一个参数,表示想要删除或插入的元素的索引值。
第二个参数是删除元素的个数(这个例子里,我们的目的不是删除元素,所以传入0)。
第三个参数往后,就是要添加到数组里的值(元素2、3、4)。
输出会发现值又变成了从-3到12。
最后,执行以下这行代码。
numbers.splice(5,3,2,3,4);
输出的值是从-3到12。原因在于,我们从索引5开始删除了3个元素,但也从索引引5开始添加了元素2、3、4。
- 二维数组和多维数组
还记得本章开头平均气温测量的例子吗?现在我打算再用一下这个例子,不过把记录的数据改成数天内每小时的气温。现在我们已经知道可以用数组来保存这些数据,那么要保存两天内每小时的气温数据就可以这样做。
let ms1 = [72,75,79,79,81,81];
let ms2 = [81,79,75,75,73,72];
然而,这不是最好的方法,还可以做得更好。我们可以使用矩阵(二维数组,或数组的数组来存储这些信息。矩阵的行保存每天的数据,列对应小时级别的数据。
let msTemp = [];
msTemp[0] = [72,75,79,79,81,81];
msTemp[1 = [81,79,75,75,73,72];
JavaScript只支持一维数组,并不支持矩阵。但是,我们可以像上面的代码一样,用数组套数组,实现矩阵或任一多维数组。代码也可以写成如下这样。
// day 1
msTemp[0] = [];
msTemp[0][0] = 72;
msTemp[0][1] = 75;
msTemp[0][2] = 79
msTemp[0][3] = 79;
msTemp[0][4] = 81;
msTemp[0][5] = 81;
// day 2
msTemp[1] = [];
msTemp[1][0] = 81;
msTemp[1][1] = 79;
msTemp[1][2] = 75
msTemp[1][3] = 75;
msTemp[1][4] = 73;
msTemp[1][5] = 72;
上面的代码里,我们分别指定了每天和每小时的数据。数组中的内容如下图所示。
每行就是每天的数据,每列是当天不同时段的气温。
要在浏览器控制台中打印二维数组,还可以使用 console.table(msTemp) 语句。它会显示一个更加友好的输出结果。
多维数组
我们也可以用这种方式来处理多维数组。假设我们要创建一个3×3×3的矩阵,每一格里包含矩阵的i(行)、j(列)及z(深度)之和。
const matrix3x3x3 = [];
for(let i=0;i<3;i++){
matrix3x3x3[i] = [];
for(let j=0;j<3;j++){
matrix3x3x3[i][j] = [];
for(let z=0;z<3;z++){
matrix3x3x3[i][j][z] = [];
}
}
}
数据结构中有几个维度都没关系,我们可以用循环迭代每个维度来访问所有格子。
3×3×3的矩阵立体图如下所示。
手绘功底有限,我已经尽力了。。。 这立体图实在画不正。。。【/捂脸】
三、JavaScript数组方法参考
方法 | 描述 |
---|---|
concat | 连接2个或更多数组,并返回结果 |
every | 对数组中的每个元素运行给定函数,如果该函数对每个元素都返回true,则返回true |
filter | 对数组中的每个元素运行给定函数,返回该函数会返回true的元素组成的数组 |
forEach | 对数组中的每个元素运行给定函数。这个方法没有返回值 |
join | 将所有的数组元素连接成一个字符串返回 |
indexOf | 第一个与给定参数相等的数组元素的索引,没有找到则返回-1 |
lastIndexOf | 返回在数组中搜索到的与给定参数相等的元素的索引里最大的值 |
map | 对数组中的每个元素运行给定函数,返回每次函数调用的结果组成的数组 |
reverse | 颠倒数组中元素的顺序,原先第一个元素现在变成最后一个,同样原先的最后一个元素变成了现在的第一个 |
slice | 传入索引值,将数组里对应索引范围内的元素作为新数组返回 |
some | 对数组中的每个元素运行给定函数,如果任一元素返回true,则返回true |
sort | 按照字母顺序对数组排序,支持传入指定排序方法的函数作为参数 |
toString | 将数组作为字符串返回 |
valueOf | 和tostring类似,将数组作为字符串返回 |
下表列出了ES2015和ES2016新增的数组方法。
方法 | 描述 |
---|---|
@@iterator | 返回一个包含数组键值对的选代器对象,可以通过同步调用得到数组元素的键值对 |
copyWithin | 复制数组中一系列元素到同一数组指定的起始位置 |
entries | 返回包含数组所有键值对的@@iterator |
includes | 如果数组中存在某个元素则返回true,否则返回false |
find | 根据回调函数给定的条件从数组中查找元素,如果找到则返回该元素 |
findIndex | 根据回调函数给定的条件从数组中查找元素,如果找到则返回该元素在数组中的索引 |
fill | 用静态值填充数组 |
from | 根据已有数组创建一个新数组 |
keys | 返回包含数组所有索引的@@iterator |
of | 根据传入的参数创建一个新数组 |
values | 返回包含数组中所有值的@@iterator |
本章的方法仅供参考,万一本文年代久远了,可能就会缺失新增的方法。
四、本章小结
本章,我们学习了最常用的数据结构:数组。不仅学习了如何声明和初始化数组、给数组赋值,以及添加和删除数组元素,还学习了二维、多维数组以及数组的主要方法。这对我们在后面章节中编写自己的算法很有用。
由于时间问题,就没有对每个数组的方法进行演示,若有不懂的地方,需要的话可以去“菜鸟教程网”看一下每种数组方法具体的用法。
五、写在后面
这作为一个JavaScript数据结构与算法的数组篇文章,主要目的是让学习JavaScrip的数组结构,以及常用的数组操作方法,把本文读懂,在后面的“栈”数据结构中会有很大的益处,而且在项目开发中,数组也是常用的数据结构之一,祝您生活学习愉快,本系列也会持续进行更新的。
有问题请留言或者@博主,谢谢支持o( ̄︶ ̄)o~
感谢您的阅读,如果此文章或项目对您有帮助,若可以的话请给个一键三连吧!
GitHub有开源项目,需要的小伙伴可以顺手star一下!
GitHub: https://github.com/langyuxiansheng
以上是关于手把手5分钟入门JavaScript数组,万字文超详细手绘操作执行过程②JavaScript数据结构与算法系列的主要内容,如果未能解决你的问题,请参考以下文章
手把手5分钟入门JavaScript数组,万字文超详细手绘操作执行过程②JavaScript数据结构与算法系列