一、数组常识
1、数组是个特殊的对象
# 数组属于“特殊的对象”。
为了验证数组属于特殊的对象。我们不妨通过打印数组的方式,看看调试器的显示结果。
首先我们应该搞清楚怎样才能知道数组的类型呢?
这个问题还是挺简单的,可以直接通过console.log(typeof 待测试的数组)的方式,打印在控制台上。
我们在代码中运用起来看一下数组属于什么类型。
最后,来到调试器里看一下输出的结果。
# 从这一点就能够看出数组是一个对象。只是这个对象长的比较奇怪而已。
2、查看数组的数据结构
既然我们知道了数组是一个对象,那么自然可以使用
console.dir()来进行检查。看看输出的效果。
运行一下,看看结果。
我们不妨点击展开一下
我们要简单的说明一下数组的数据结构。
你会发现在在编写代码的时候,代码中的数值其实对应的是键值对的“值”。
以数字从0开始逐级递增的部分叫做键值对的"值",也能够用来代表位置的数字
索引。
总结一下,你会是下面这个样子。
比较特殊的是,数组会默认有一个
length属性名
# 我们可以用“length属性”,编写很多复杂的逻辑代码。不容小视。
3、对比一下对象的数据结构
那么我们还记得对象的数据结构吗?我们不妨模拟一下。
运行一下,看看结果。
我们不妨点击展开一下
# 可以看出数组和对象是非常相似的。
我们完全可以用对象的形式重新将数组重写一下。
# 数组和对象对比的结论是:
1、数组和对象可以说非常的相似,本质上数组还是对象,只不过数组是一个特殊的对象。
2、数组中并不需要我们手动的设置"属性名",默认由"索引"替代。
3、数组自带length属性名,其中长度会自动的计算出来。编写代码的时候可以直接拿来使用。
4、数组小技巧
在使用数组的时候,有些小技巧需要我们看到数组的时候,脑海中就能够马上反应出来。
# 索引
所谓
索引就是数组中默认生成的,从0开始逐级递增的属性名叫做索引。(如下图所示)
索引也叫做键值对中的“键”,也叫键值对的“key”,也叫属性名。但是官方的叫法叫做索引;
# 获取指定项的内容
我们可以通过索引来获取指定项的内容。
# 比如我们现在要获取数组中的第一项(指定项)的内容。
运行一下,你会发现输出第一项内容为
12
从上面的现象中,也说明了一点,"位置1" 对应的是 "索引0",千万不要认为是"索引1";
# 获取数组中的长度
前面我们有提到,数组中默认会存在一个属性,叫做
length属性。代表的是长度。
那么我们可以通过
ary.length的方式,可以获取数组的长度。
运行之后,就能够看出数组中的长度。
# 获取最后一项的索引
请问什么叫做获取最后一项索引呢?
其实直接通过图片的方式进行理解就方便很多了。
要想获取最后一项的索引,那么必须要我们理解
索引是从0开始逐级递增的。
只有理解了这一点,那么我们编写起来就非常的简单了。其实你会发现最后一项索引和数组长度存在关联性
也就是可以通过ary.length-1的方式,就能够获取最后一项的索引。
我们用代码的形式模拟一下。
运行一下,看看效果。
# 上面这些数组中的小技巧,其实通过分析数组的数据结构,都是可以分析出来的。不需要我们可以的去死记,只要你能够理解什么是索引?什么是数组的长度?那么问题就解决了。
二、数组有什么常用的方法(摘要)
遍历数组方法的简单介绍
说到遍历数组的方法,那么到底可以有多少个方法呢?
有forEach、map、filter、find、reduce、some、every及其他方法。
需要知道的是操作数组的方法实在是太太太重要了。只要你操作数据那么上面的这些方法你都要学会。更何况后面我们在学习vue和react这种以数据来影响视图的前端框架,那么数组这一块的内容可以说是天天在操作。因此上面的这些方法是我们一定要学会的,甚至能背出来的方法。
首先我们需要知道的是:我们在学习数组的常用方法时,我们需要按照四个维度来记忆。
# 1、方法的作用和含义
需要知道这个方法到底是干啥的?
# 2、方法的实参(包括类型和含义)
执行方法时,可以给方法传递参数。那么我们到底给方法传递什么参数呢?是需要我们搞清楚的。
# 3、方法的返回值
执行方法后,会返回一个什么值?
# 4、原来的数组是否会发生改变
有些方法会将原始数组的数据进行修改。需要我们进行区分。
其实,对于这些方法来说,没有什么可以用逻辑进行思考的,主要还是在于背。背的越熟越好。在使用的时候,能够快速的反应出来,那么再稍微查阅一下,然后使用起来,那么这就够了。
1、新增内容:push方法
需要注意的是,增删改的这一部分方法都会修改原有的数组。
# push方法
# 1、方法的作用和含义
push方法的作用是向数组末尾增加内容。
# 2、方法的实参(包括类型和含义)
可以传入“多个任意类型”的参数,可以增加一个,也可以增加很多个。
# 3、方法的返回值
返回新增后的数组长度。
# 4、原来的数组是否会发生改变
会修改原有的数据。
我们不妨举个栗子。我们试图将数字、字符串、对象。添加到ary数组中。
重点看一下返回的结果。这一点非常的重要。
# 原生JS方法
我们不妨思考一下,除了使用
push方法以外,还有其他方法能够在数组的最后面添加内容吗?
我们不妨测试一下,代码如下所示:
然后运行一下,你会发现,既然成功了。
你想过为什么可以通过这种方式添加数据吗?
之所以能够这样简单粗暴的方式直接添加,是因为JavaScript是动态语言特性决定的。它不像Java和C#这一类的静态语言。JavaScript可以在不提前定义的情况下直接添加不同类型的数据。
完善一下代码,避免代码被写死了。
我们可以用
数组的长度,替代掉最后一个索引+1的代码,最终的代码如下。
运行一下,看看是不是和前面的运行结果一样。
# 这种方式是,基于原生JS操作键值对的方式,也可以向末尾添加一项新的内容。
你也会发现,其实使用push方法来添加。要比原生的JS来添加内容要好用很多。毕竟push方法是封装好的方法。编写代码的时候,优先选择push方法。特殊情况下,这个方法也不是不能用。
2、数组遍历 forEach方法
# forEach方法的理解技巧
要想理解
forEach方法,还是要从四个维度上进行分析
# 1、方法的作用和含义
forEach方法:是用来遍历数组中的每一项内容
# 2、方法的实参(包括类型和含义)
参数是:回调函数
# 3、方法的返回值
返回值:没有
# 4、原来的数组是否会发生改变
原来数组不会发生变化
# 基于原生JS中的循环
如果我们在没有讲解forEach方法之前,想要遍历数组中的每一项内容的时候,可以怎么做呢?
在没有forEach方法之前,我们可以基于原生JS中的循环就可以实现遍历数组中每一项内容的功能。
let ary = [12, 15, 9, 28, 10, 22];
for(let i=0;i<ary.length;i++){
// i:代表的是当前循环的索引。
// ary[i]:根据索引获取循环的某一项值。
console.log('索引:'+i+'内容:'+ary[i]);
}
我们把上面这段代码编写在编辑器中。
然后运行一下看看,显示的结果。
我们可以看出,通过普通的for循环,就能够实现遍历数组中每一项内容的功能。
除了通过原生JS中的循环方式以外,我们还可以通过调用方法的方式来实现相同的效果。也就是下面我们要用到的forEach方法。
# forEach方法的使用技巧
还是原来的数组,我们看看如何用forEach方法来遍历出每一项内容的功能
let ary = [12, 15, 9, 28, 10, 22];
首先,我们需要用
“需要遍历的数组ary”来开头,再调用forEach方法。这种方式看起来会比较怪。
然后,我们将回调函数作为参数传递进去。
需要注意的是,数组中有多少项,那么里面的回调函数就会默认执行多少次。
你会发现。回调函数里面有了两个参数,分别是
item和index。
那么我们看一下这两个参数分别代表着什么含义。
当每一次执行回调函数的时候,那么item和index表示的意思如下:
# item:是数组中当前要操作的这一项。
# index:是数组中当前项的索引。
换句话说,其实
item对应着for循环中的ary[i],而index对应着for循环中的i
为了证实这一点,我们也用for循环中的打印方法,改一下参数。
打印出来,看看效果。
你会发现,"for循环"和"forEach方法"打印出来的效果是一模一样的。
其实通过forEach方法写出来的代码会更加简单和易于维护,后面我们如果需要用到遍历数组,那么我们可以首先考虑去使用forEach方法来进行编辑。
需要注意的是,类数组是不能使用forEach方法来遍历的。只有数组才能使用forEach方法来进行遍历。虽然说for循环也可以遍历数组,但是在编程中,大多还是采用forEach方法的。
后续会学习到另一种特殊的方法,这个方法是可以通过JS封装一个比官方给的forEach方法还要好用的Each方法,Each方法不仅仅是可以遍历数组,还可以遍历对象,还可以遍历类数组。
最后,我们我们格式化一下代码的话,会出现一定程度的变化。需要我们能够识别出来。
如果你在开发的时候,没有用到index索引的时候,其实还可以对代码进行优化。
如果是index索引被省略掉了,其实按照箭头函数的规则,只有一个参数的话,可以省略小括号。
知道这里面的小细节,可以在编程中省略很多的代码,提升代码美观度。熟悉以后,可以提升开发效率。
# myforEach的封装
在遍历数组的时候,有没有想过有了for循环的情况下,为什么官方还提供forEach方法?
要知道在forEach方法没有出来之前,我们可以使用基于原生JS中的循环(就是使用for循环)就可以实现遍历数组中每一项内容。如下所示:
let ary = [12, 15, 9, 28, 10, 22];
for(let i=0;i<ary.length;i++){
// i:代表的是当前循环的索引。
// ary[i]:根据索引获取循环的某一项值。
console.log('索引:'+i+'内容:'+ary[i]);
}
我们把上面这段代码编写在编辑器中。
然后运行一下看看,显示的结果。
# 我们可以看出,通过普通的for循环,就能够实现遍历数组中每一项内容的功能。
但是除了使用for循环以外,我们还可以通过另一种方式来编写。也就是使用forEach方法来进行遍历数组中的元素。代码如下所示:
let ary = [12,15,9,28,10,22];
ary.forEach(
(item,index)=>{
console.log('索引:'+index+'内容:'+item);
}
)
# 运行之后,你就可以发现使用forEach的方法就是实现相同的效果。
那么这个时候,你有没有想过,forEach方法里面是如何实现数组的遍历的呢?
其实答案很简单,其实forEach方法的本质还是for循环。只不过for循环被封装成了回调函数。for循环和forEach方法本质上是一样的,只是在外界使用的方式上看上去显的不一样。
那么为什么还要多次一举的将for循环封装成forEach方法呢?
其实我们单纯从代码上进行比较的话,就能看出来,在使用forEach方法的时候,要比for循环要好用很多。在使用forEach方法的时候,我们并不需要考虑“i++”这类的递增关系。只需要关注item和index。就是完成遍历的操作。因此通过封装的代码,会让代码变得更加的方便的使用。日后的代码维护也变得方便很多。这就是为什么需要大费周章过的对for循环进行封装的原因。
如何证明forEach方法的本质就是for循环呢?
最直接的方法,自然是直接查看源码。这里我就不介绍了,我们来个更好玩的,我们试试用回调函数的方法来封装一个属于自己的forEach方法。实现和forEach方法相同的效果。
具体封装过程:
我们可以看出这个通过for循环遍历的话,代码是这样的。
而forEach方法,本质上就是对for循环的封装。而封装的方式是通过回调函数进行封装的。
# 回调函数:编写在方法中的函数。
因此首先我们需要编写一个方法用来管理for循环。
然后,我们需要在方法中添加fn参数。其中fn代指的是方法。
接下来,我们就要考虑fn函数的编写情况了。我们需要考虑的是,需要遍历的数据是什么?
但是这会有个问题是,我们不能直接使用ary,因为这样的话会限制我们封装的代码。
我们应该将数组的名称决定权交给调用者。我们可以用this来指代需要遍历的数组名称。
接下来我们重点看一下如何编写fn函数。其实就是对打印出来的结果进行改造。
# 其实这样就算封装完毕了,是不是很简单。
如果是在前端使用的话,我们还需要将自己定义的myForEach方法定义到Array.peototype中。在微信小程序中使用自己定义的myForEach方法的话。只需要引入就可以使用。没有这么麻烦。
打印出来看下结果。
当传递进去之后,那么我们在后续遍历数组的时候,myForEach方法才会起到作用。这个时候我们试着使用起来。
为什么需要使用这么奇怪的调用方法结构。
ary.myForEach()
其实原因在于我们在编写myForEach方法的时候,为了能够封装一个通用性较强的方法,我们用了this来替代数组名称。(前面已经说过)。既然在封装的时候没有规定是哪一个特定的数据,那么我们在使用的时候,就需要先告诉一下myForEach方法需要使用的具体数组名,然后再使用方法。也就是这样的ary.myForEach()结构。
那么这个时候,我们需要如何使用myForEach方法呢?
这个你需要知道的是,index参数内部存储的就是for循环中的索引i,item参数内部存储的是for循环中的值。
然后我们就可以执行遍历数组了。
打印出来看一下效果
# 这就把forEach方法的效果给模拟出来了。可以看出forEach方法本质就是for循环。只不过我们通过回调函数的方式将for循环进行了封装。
细心的你会发现,其实myforEach方法的使用方式和数组内置的forEach方法的使用方法是一样的。
我们还可以完善一下代码,如下所示:
最终打印出来的结果如下:
可以看出,本质上还是通过回调函数的形式进行来封装。
上篇的案例来源于:www.jianshu.com/p/a07975ae2…