前言:
集合对象(array、set、map)其实是一种泛型,在js中没有明确的规定其内元素的类型。遍历Array可以采用下标循环,遍历Map和Set就无法使用下标。为了统一集合类型,ES6标准引入了新的iterable类型,Array、Map和Set都属于iterable类型,具有iterable类型的集合可以通过新的for of循环来遍历,并且都内置forEach方法。
首先先说一下3种for循环:
- for in循环是es5的一种循环方式,它遍历的实际上是对象的属性名称。常用于遍历对象的属性,也可以遍历数组的键名,因为一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。当我们手动为数组加一个属性的时候,for in也会将手动添加的属性遍历出来,同时, for in会将对象原型链上的属性与方法也遍历出来。如果我们需要用for in的时候并不需要原型链上的属性或方法,可以用hasOwnProperty()来进行过滤。
如:
a = [1,2,3];
a.name = 'dwb';
for ... in 之后打印 // 0,1,2,'name'
- for of循环是es6新引入的一种循环方法,他相较于刚才说的for in,在循环数组的时候完全修复了这些问题,它只循环集合本身的元素。但是他只能遍历数组或者伪数组,他并不能遍历一个原生的对象。
如:
a = [1,2,3];
a.name = 'dwb';
for ... of 之后打印 // 1,2,3
- forEach循环是es5引入的一种循环方式,他是for循环的简便写法,但是只能循环数组,不能遍历对象。
接下来说一下集合对象,Set是ES6提供的新的数据结构, 类似于数组, 但是它的成员是唯一的, 不能重复。Map也是ES6提供的新的数据结构, 本质上是键值对的集合(Hash 结构), 但是传统上只能用字符串当作键。这给它的使用带来了很大的限制,所以ES6中新增了Map数据结构, 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
在日常的业务操作中,经常会遇到对数据的操作,选择一个合适的操作方法其实很重要,可以事半功倍。而且可以简化代码。下面来说一下常用的一些数组方法。
- Array:
1.push() // 向数组的末尾添加一个或多个元素,并返回新的长度
2.pop() // 删除并返回数组的最后一个元素。
3.unshift() // 向数组的开头添加一个或更多元素,并返回新的长度。
4.shift() // 把数组的第一个元素从其中删除,并返回第一个元素的值。
5.sort() // 数组排序,无参数时默认对String进行ASCLL码进行升序排序,可以传方法,对数组元素进行升序或者降序排序
6.reverse() // 反转数组,将数组倒序排列
7.concat() // 拼接数组,该方法会先创建当前数组的一个副本,无参数的情况下, 直接返回副本, 有参数的情况下, 将参数中的数组元素添加到数组的尾部
8.slice() // 数组截取,基于当前数组中的一项或多项返回一个新的数组
9.splice() // 数组增、删、改
删除: 2个参数, 从第几项开始删和删除几项 splice(0, 1)
插入: 起始位置, 要删除几项(填0), 要插入的项(可以写多个参数) splice(1, 0, "black", "green",....)
替换: 起始位置、要删除的项、要插入的项 splice(1, 1, "yellow")
10.数组查找、过滤:
1.indexOf() 参数:值 返回某个指定的值在数组中首次出现的位置,必须给定元素
[1,2,2,3].indexOf(2) // 1
2.lastIndexOf() 参数:值 返回某个指定的值在数组中最后一次出现的位置,必须给定元素
[1,2,2,3].indexOf(2) // 2
3.findIndex() 参数:函数 返回满足传入函数判定条件且在数组首次出现的元素的位置
[1,2,2,3,4,5].findIndex( i => i === 2 ) // 1
4.includes() 参数:值 判断一个数组是否包含一个指定的值,如果是返回 true,否则false
[1,2,2,3].includes(2) // true
5.map() 参数:函数 返回一个新数组,数组中的元素为原始数组元素按顺序依次调用函数处理后的值
[4, 9, 16, 25].map(Math.sqrt) // 2,3,4,5
6.filter() 参数:函数 返回一个新数组,返回满足传入函数判定条件的所有值
[1,2,2,3,4,5].filter( i => i > 3 ) // 4,5
7.find() 参数:函数 返回满足传入函数判定条件的第一个元素的值
[1,2,2,3,4,5].find( i => i > 3 ) // 4
8.some() 检测数组中的元素是否满足指定条件(函数提供)
9.every() 检测数组所有元素是否都符合指定条件(函数提供)
- Set:
1.add() // 添加一个元素,支持链式操作 add('nihao') // 返回set
2.delete() // 删除 delete('nihao') // true
3.has() // 判断是否存在 has('nihao') // false
4.可以通过Set里的值不会重复的特性进行两个数组合并去重等操作
let a = new Set([1,2,3]);
let b = new Set([4,3,2]);
Array.from(new Set([...a,...b])) // 1,2,3,4
- Map:
1. size() 获取Map元素个数
1. isEmpty() 判断Map是否为空
1. clear() 删除Map所有元素
1. put(key, value) 向Map中增加元素(key, value)
1. remove(key) 删除指定key的元素,成功返回true,失败返回false
1. get(key) 获取指定key的元素值value,失败返回null
1. element(index) 获取指定索引的元素(使用element.key,element.value获取key和value),失败返回null
1. containsKey(key) 判断Map中是否含有指定key的元素
1. containsValue(value) 判断Map中是否含有指定value的元素
1. keys() 获取Map中所有key的数组(array)
1. values() 获取Map中所有value的数组(array)
Array、Map、Set都有自己的特点,那么当遇到一些特定的业务场景的时候,选取适合的数据结构去处理业务无疑会提高代码的优雅性,而且会让事情变得更简单。
那么他们的特性如何呢?
Array:
Array使用了汇编、C++、JS三种语言实现,它的功能可以说是非常强大的,JS中的array是一个万能的数据结构,因为首先它可以当作一个普通的数组来使用,即通过下标找到数组的元素,然后它可以当作一个栈来使用,我们知道栈的特点是先进后出,栈的基本操作是出栈pop()和入栈push(),同时它还可以当作一个队列,队列的特点是先进先出,基本操作是出队shift()和入队push(),甚至它还可以当作一个哈希表来使用map["name"] = "yin"; (但是不推荐这么用),另外,它还可以随时随地增删数组中任意位置的元素splice()。
JS Array有两种模式,一种是快速的,一种是慢速的,快速的用的是索引直接定位,慢速的使用用哈希查找,比如当增加一个2000的索引时( var array = [1, 2, 3]; array[2000] = 10; ),array就会被转成慢元素。为什么说JS Array非常强大呢,这是因为它提供的一些操作方法的实现很便捷,而且都做了不同情况下的处理,比如像sort()这个排序函数,他本身的实现方法使用的是快速排序,但当数组的元素个数不超过10个的时候,用的是插入排序。当然还有很多的方法也都采用了不同的情况不同的方式去操作。使用者不需要关心各个数据结构的区别是什么,同时他还变相的屏蔽掉了数据结构的概念,使得使用者即便不知道栈、队列、哈希(map)、树等结构,就可以便捷的使用。
Set:
Set类似于数组,相比于Array,Set其实有很独特的优点,就是Set里的值,一定是唯一的。并且可以通过key去查找,查找速度也很快。所以当在业务场景里遇到需要在大量的数据中去精准定位某一个单一的元素的时候,如果使用Set这种数据结构去查找将会提升巨大的代码运行速度,但是所需要注意的是,Set的另一个特性,就是Set中的所有的值都是唯一的,当然,Number类型和String类型会被区分,类似于 === ,也就是说 5 和 ‘5’ 会被认定为两个不同的值,而且NaN值也可以被保存,但是只能有一个。而在Array中,你无法使用indexOf()或者includes()去定位NaN值的位置,但Set可以并且可以存储他。而关于对象,在Set中,即便两个对象看起来值相等,但是依然会被认为是两个不同的值。
说到对象,还有一个结构与Set类似,也是不重复的值的集合,他就是WeakSet。但是,他与Set有两个区别。第一,WeakSet成员只能是对象,而不能是其他类型的值。第二,WeakSet中的对象都是弱引用,即GC(垃圾回收机制)不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不在引用该对象,那么GC会自动回收该对象所占用的内存,不会考虑该对象是否还存在于WeakSet中。当我们在写业务的时候,有时候会经常忘记手动取消引用,释放内存,有时候就可能会造成内存泄漏,严重影响性能。当然WeakSet就不存在这种问题,所以,WeakSet适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,在WeakSet中的引用就会自动消失,然后被GC清理掉。当然,需要注意的是,由于WeakSet的特点,他的成员是不适合被引用的,因为他会随时消失,如果直接引用的话,可能会在某一时刻造成空指针异常而导致程序崩溃。同时因为WeakSet里的某些成员可能随时会被GC清除,在清除前后成员的个数是不一样的,所以在ES6中规定,WeakSet不可被遍历。
Map:
- 在JS中,对象的本质上是键值对的集合( 哈希(hash)结构 ),但是只能用字符串作为键,这给他的使用带来了很大的限制。为了解决这个问题,ES6提供了Map数据结构,它类似与对象,也是键值对的集合,但是“键”的范围并不限于字符串,各种类型的值,甚至包括对象,都可以当作键。也就是说,Object结构提供了“字符串-值”的对应,而Map结构提供了“值-值”的对应。如果需要“键值对”的数据结构,Map其实比Object更合适。相比于Array,Map的查找速度极快。在业务场景中,当遇到需要查找内容的时候,如果数据量很大,在Array中查找耗时会很长,耗的时间与Array的长度成正比,同时也与超找元素的位置坐标有影响,很不稳定。但是如果在Map中实现,只需要一个key,便可查找到value,无论这个数据量有多大,查找速度都不会变慢。需要注意的是,相比于Set,Map中遇到相同的key时,后加入的key值所对应的value值,会覆盖掉之前的value。
以上仅是本人学习过后做出的总结与归纳,如笔记有误,请指教~
(限于本人技术有限,本文如有表述不当的地方,欢迎赐教~)
(转载到其他平台请包含本文的简书链接或说明出处~)