除了Object之外,Array类型应该是ECMAScript中常用的类型,并且javaScript中的Array类型和其他语言中的数组非常的不同,本文将由浅入深地从 创建Array类型和 原型方法两个大方向带大家彻底理解这个ECMAScript中的重要类型
一、创建Array类型
1.1 创建数组
创建数组有两种基本方式,第一种是使用Array构造函数
第二种是数组字面量表示法,由一对包含数组项的方括号表示,多个数组之间以逗号隔开。
1.2 不限制类型
javaScript中的Array类型和其他语言一样都是数据的有序列表,但是因为javaScript是弱类型语言的关系,与其他语言不同的是,javaScript的每一项数组元素可以存放任何类型的数据
可以看到Array数组可以包容任何类型的数据
1.3 数组length
javaScript的数组大小也与其他语言有不尽相同的地方,javaScript的Array类型是支持动态调整的,即可以随着数据的添加自动增长以容纳新的元素,与别的语言相同,Array类型同样也是用length来访问数组的长度大小。
同时,数组的length属性很有特点—它不只是只读的,因此通过这个属性,是可以从数组的末尾移除项或者添加项的
二、原型方法
2.1 转换方法
Array类型在原型处封装了三个方法用于数组转换,values(),toString(), toLocaleString()。
values()返回的包含数组所有元素的一个新的Iteractor对象(不知道Iteractor对象的同学可以Bing一下,或者看我后面写的关于Iteractor对象的文章)
toString()返回的是数组每个值的字符串形式并用一个逗号分隔拼接而成的字符串
toLocaleString()和toString()结果相似,不过是返回的是方法下的toLocaleStrng()方法
可以看到toString()和toLocaleString()方法是调用了数组元素对应的方法来把返回值拼接起来的,而values()返回的迭代器对象遍历出来正好就是数组的每个元素
2.2 数据添加移除方法
javaScript提供了让数组实现栈和队列的方法,栈是一种先进后出的数据结构,即最新添加的项目最早被移除,队列是一种先进先出的数据结构,最新添加的项目最晚被移除
push():向数组末尾添加元素
pop():移除数组末尾的元素
shift():移除数组前端的元素
unshift():向数组前端添加元素
使用push()和pop()就可以像栈一样使用数组,使用shift()和push()方法,就可以像队列一样使用数组
2.3 重排序方法
Array类型提供了reverse()方法和sort()方法用于数组的重排序,reverse()方法用于反转对应的数组,sort()方法将按对应的排序方式进行排序,默认采用升序的排序, 当然也可以自己定义compare方法来定义排序的方式
与C++等语言compare不同的是,js的compare方法不能支持对bool值的返回,也就是说类似下面写法的compare方法没办法进行排序
js比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相同返回0,如果第一个参数应该位于第二个之后则返回一个正数
这里提供了一个降序排序的写法,大家可以结合代码自己实现一下。
2.4 sort方法底层实现的算法
ECMAScript 不同版本规范对 Array.prototype.sort 的定义中没有要求用什么样的排序方式实现 sort() 方法,也没有要求是否要采用稳定排序算法
因此各浏览器都给出自己的实现方式:
表格内容部分来自于维基百科
浏览器 | 使用的 JavaScript 引擎 | 排序算法 |
Google Chrome | V8 | 插入排序和快速排序 |
Mozilla Firefox | SpiderMonkey | 归并排序 |
Safari | Nitro(JavaScriptCore ) | 归并排序和桶排序 |
Microsoft Edge 和 IE(9+) | Chakra | 快速排序 |
下面是相关算法的时间复杂度
排序类型 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
快速排序 | O(nlogn) | O(nlogn) | O(n²) | O(nlogn) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(nlogn) | 稳定 |
插入排序 | O(n²) | O(n) | O(n²) | O(1) | 稳定 |
桶排序 | O(n+k) | O(n+k) | O(n²) | O(n+k) | (不)稳定 |
辅助空间大家可以理解成是算法执行过程中所需要的空间,O(1)是最理想的, 因为这样的算法其辅助空间不依赖于问题的规模,换句话说这样的算法是稳定的。
大家可以看到,各个浏览器对sort的底层实现方式都是不同的,这里也可以看到IE所使用的快排在最坏的情况是可以达到O(n^2)的复杂度的,这里给出一张不同复杂度排序算法在不同的数据量下的响应时间表帮助大家理解我下面将要谈到的问题
不难看到,当数据量达到10W以后,O(n^2)的排序方法是需要3-4min的,对于的网页渲染肯定是及其不好的,所以我们其实可以知道,用原生的sort方法,不同浏览器的实现不同,意味着会有性能上的不同和兼容性,尤其在面对大数量的数据面前,这个问题暴露得尤为明显
所以,当大家要在前端进行数据的排序处理的时候,要注意数据量会不会导致不同浏览器的渲染效果出现明显差异,如果出现了卡顿或者处理时间过长的问题,自己封装一个稳定的排序函数,以保持各浏览器的一致性。
2.4 操作方法
这一小节要和大家介绍的是Array类型最常用的三个操作方法:concat(),slice(),splice()
concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
----《MDN web docs》
上面三个方法除了splice方法以外都是返回一个新的数组对象,而不会对原始数组改变,concat方法起一个合并数组的作用,slice方法是对数组的一个浅拷贝(具体什么是浅拷贝将在下一小节具体说明),而splice方法的功能最为强大,可以删除,可以增添,也可以替换数组的元素。splice方法有三个参数,第一个参数是操作的起始位置,第二个是删除元素的个数,如果是0,就不进行删除操作,第三个参数可以有多个,是要添加进数组的元素,会从第一个参数的起始位置开始添加。
2.5 浅拷贝和深拷贝
深拷贝和浅拷贝只针对Object和Array这样的引用数据类型。
具体到底应该怎么区分浅拷贝和深拷贝呢?
简单来说,就是假设B复制了A,为修改A时,看B是否会变化,如果B也跟着变了,说明这是浅拷贝,拿人手短。如果B没变。那就是深拷贝,自食其力
2.6 其他方法
Array类型其他的方法,并不是说这些方法不重要,只是ES6中已经有了对于下面方法很好的替代,所以这里就不再对这些方法做具体的解释了,如果感兴趣的同学可以到MDN上查阅相关的方法
进入MDN查阅更多Array类型原型方法
三、总结
1、Array类型支持在一个数组对象中包含不同的数据类型
2、Array类型支持内存的动态调整,并且length属性不只是一个只读对象,通过调整这个属性甚至可以对数组对象进行增删的操作
3、Array类型实现了像栈和队列的数据结构的操作,使用push()和pop()可以像栈一样使用数组,使用shift()和push()可以像队列一样使用数组
4、sort方法支持自定义compare方法进行排序,不支持对bool型的返回,只支持对数字的返回
5、sort方法在不同浏览器中的底层实现方式和算法复杂度都不同,可能出现浏览器渲染效率有差异和数据量巨大情况下浏览器卡顿的情况,要解决这个问题,需要不在前端进行数据的排序,或者自己写一个稳定的排序函数来统一原生的sort方法。
小伙伴们今天的学习就到这里了,如果觉得本文对你有帮助的话,欢迎转发,评论,收藏,点赞!!!