在使用js编程的时候,常常会用到集合对象,集合对象其实是一种泛型,在js中没有明确的规定其内元素的类型,但在强类型语言譬如Java中泛型强制要求指定类型。

ES6引入了iterable类型,Array,Map,Set都属于iterable类型,它们可以使用for...of循环来遍历,都内置forEach方法。

数组

遍历

普通遍历

最简单的一种,也是使用频率最高的一种。

  1. let arr = ['a', 'b', 'c', 'd', 'e']
  2. for (let i = 0; i < arr.length; i++) {
  3. console.log(i, ' => ', arr[i])
  4. }

优化: 缓存数组长度:

  1. let arr = ['a', 'b', 'c', 'd', 'e']
  2. for (let i = 0, len = arr.length; i < len; i++) {
  3. console.log(i, ' => ', arr[i])
  4. }

使用临时变量,将长度缓存起来,避免重复获取数组长度,当数组较大时优化效果才会比较明显。

for-in

这个循环很多人爱用,但实际上,经分析测试,在众多的循环遍历方式中它的效率是最低的。

  1. let arr = ['a', 'b', 'c', 'd', 'e']
  2. for (let i in arr) {
  3. console.log(i, ' => ', arr[i])
  4. }

for-of

这种方式是es6里面用到的,性能要好于forin,但仍然比不上普通for循环。

  1. let arr = ['a', 'b', 'c', 'd', 'e']
  2. let index = 0
  3. for (let item of arr) {
  4. console.log(index++, ' => ', item)
  5. }

forEach

数组自带的foreach循环,使用频率较高,实际上性能比普通for循环弱。

  1. let arr = ['a', 'b', 'c', 'd', 'e']
  2. arr.forEach((v, k) => {
  3. console.log(k, ' => ', v)
  4. })

forEach接受第三个参数,指向原数组,没有返回值,对其进行操作会改变原数组对象

  1. let ary = [12, 23, 24, 42, 1]
  2. let res = ary.forEach((item, index, input) => {
  3. input[index] = item * 10
  4. })
  5. console.log(res) //-->undefined
  6. console.log(ary) //-->会对原来的数组产生改变

如果版本低的浏览器不兼容(IE8-),可以自定义方法实现:

  1. /**
  2. * forEach遍历数组
  3. * @param callback [function] 回调函数;
  4. * @param context [object] 上下文;
  5. */
  6. Array.prototype.myForEach = function (callback,context) {
  7.   context = context || window;
  8.   if('forEach' in Array.prototype) {
  9.     this.forEach(callback,context)
  10.     return
  11.   }
  12.   // IE6-8下自己编写回调函数执行的逻辑
  13.   for(let i = 0,len = this.length; i < len; i++) {
  14.     callback && callback.call(context, this[i], i, this)
  15.   }
  16. }
  17. let arr = [12, 23, 24, 42, 1]
  18. arr.myForEach((v, k) => {
  19. console.log(k, ' => ', v)
  20. })

map

map会返回一个全新的数组,同样接受第三个参数,如果对其进行操作会改变原数组。

  1. let ary = [12, 23, 24, 42, 1]
  2. let res = ary.map((item, index, input) => {
  3. return item * 10
  4. })
  5. console.log(res) //-->[120,230,240,420,10]
  6. console.log(ary) //-->[12,23,24,42,1]

如果版本低的浏览器不兼容(IE8-),可以自定义方法实现:

  1. /**
  2. * map遍历数组
  3. * @param callback [function] 回调函数;
  4. * @param context [object] 上下文;
  5. */
  6. Array.prototype.myMap = function myMap(callback,context){
  7.   context = context || window
  8.   if('map' in Array.prototype) {
  9.     return this.map(callback, context)
  10.   }
  11.   //IE6-8下自己编写回调函数执行的逻辑
  12. let newAry = []
  13.   for(var i = 0,len = this.length; i < len; i++) {
  14.     if(typeof callback === 'function') {
  15.       var val = callback.call(context, this[i], i, this)
  16.       newAry[newAry.length] = val
  17.     }
  18.   }
  19.   return newAry
  20. }
  21. arr.myMap((v, k) => {
  22. console.log(k, ' => ', v)
  23. })

过滤

filter

对数组中的每个元素都执行一次指定的函数(callback),并且创建一个新的数组,该数组元素是所有回调函数执行时返回值为 true 的原数组元素。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略,同时,新创建的数组也不会包含这些元素。

  1. let arr = [12, 5, 8, 130, 44]
  2. let ret = arr.filter((el, index, array) => {
  3. return el > 10
  4. })
  5. console.log(ret) // [12, 130, 44]

map

map也可以作为过滤器使用,不过返回的是对原数组每项元素进行操作变换后的数组,而不是每项元素返回为true的元素集合。

  1. let strings = ["hello", "Array", "WORLD"]
  2. function makeUpperCase(v) {
  3. return v.toUpperCase()
  4. }
  5. let uppers = strings.map(makeUpperCase)
  6. console.log(uppers) // ["HELLO", "ARRAY", "WORLD"]

some

对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 true,如果发现这个元素,some 将返回 true,如果回调函数对每个元素执行后都返回 false ,some 将返回 false。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略。

  1. // 检查是否有数组元素大于等于10:
  2. function isBigEnough(element, index, array) {
  3. return (element >= 10)
  4. }
  5. let passed1 = [2, 5, 8, 1, 4].some(isBigEnough) // passed1 is false
  6. let passed2 = [12, 5, 8, 1, 4].some(isBigEnough) // passed2 is true

every

对数组中的每个元素都执行一次指定的函数(callback),直到此函数返回 false,如果发现这个元素,every 将返回 false,如果回调函数对每个元素执行后都返回 true ,every 将返回 true。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略。

  1. // 测试是否所有数组元素都大于等于10:
  2. function isBigEnough(element, index, array) {
  3. return (element >= 10)
  4. }
  5. let passed1 = [12, 5, 8, 1, 4].every(isBigEnough) // passed1 is false
  6. let passed2 = [12, 15, 18, 11, 14].every(isBigEnough) // passed2 is true

排序

  1. let arr = ['a', 1, 'b', 3, 'c', 2, 'd', 'e']
  2. console.log(arr) // ["a", 1, "b", 3, "c", 2, "d", "e"]
  3. console.log(arr.reverse()) // 反转元素(改变原数组) // ["e", "d", 2, "c", 3, "b", 1, "a"]
  4. console.log(arr.sort()) // 对数组元素排序(改变原数组) // [1, 2, 3, "a", "b", "c", "d", "e"]
  5. console.log(arr) // [1, 2, 3, "a", "b", "c", "d", "e"]

sort自定义排序

  1. let arr = [1, 100, 52, 6, 88, 99]
  2. let arr1 = arr.sort((a, b) => a-b) // 从小到大排序
  3. console.log(arr1) // [1, 6, 52, 88, 99, 100]
  4. let arr2 = arr.sort((a, b) => b-a) // 从大到小排序
  5. console.log(arr2) // [100, 99, 88, 52, 6, 1]
  6. console.log(arr) // 原数组也发生改变

搜索

  1. let arr = [12, 5, 4, 8, 1, 4]
  2. arr.indexOf(4) // 2,从前往后搜索,返回第一次搜索到的数组下标,搜索不到返回-1
  3. arr.lastIndexOf(4) // 5,从后往前搜索,返回第一次搜索到的数组下标,搜索不到返回-1
  4. arr.indexOf(0) // -1

增删、清空操作

添加元素

  1. let arr = ['a', 'b', 'c', 'd', 'e']
  2. arr.push(10, 11) // 模仿栈进行操作,往数组末尾添加一个或多个元素(改变原数组)
  3. arr.unshift(0, 1) // 模仿队列进行操作,往数组前端添加一个或多个元素(改变原数组)
  4. console.log(arr) // [0, 1, "a", "b", 'c', "d", "e", 10, 11]

删除元素

  1. arr.pop() // 移除最后一个元素并返回该元素值(改变原数组)
  2. arr.shift() // 移除最前一个元素并返回该元素值,数组中元素自动前移(改变原数组)
  3. console.log(arr) // ["b", "c", "d"]

清空数组

将数组的length设置为0即可

  1. let arr = ['a', 1, 'b', 3, 'c', 2, 'd', 'e']
  2. arr.length = 0

length详解:

  • 因为数组的索引总是由0开始,所以一个数组的上下限分别是:0和length-1;

  • 当length属性被设置得更大时,整个数组的状态事实上不会发生变化,仅仅是length属性变大;
  • 当length属性被设置得比原来小时,则原先数组中索引大于或等于length的元素的值全部被丢失。

splice

既可以删除也可以添加元素

  1. let arr = ['a', 'b', 'c', 'd', 'e']
  2. arr.splice(2, 1, 1,2,3)
  3. console.log(arr) // ["a", "b", 1, 2, 3, "d", "e"]

splice(start, len, elems) : 删除并添加元素(改变原数组)

  • start: 起始位置
  • len: 删除元素的长度
  • elems: 添加的元素队列
  • 几种形式:
  • splice(start, 0, elems) : 从start位置添加元素
  • splice(start, len) : 从start位置删除len个元素

截取、合并与拷贝

  1. let arr = ['a', 'b', 'c', 'd', 'e']
  2. let arr1 = arr.slice(1, 2) // 以数组的形式返回数组的一部分,注意不包括 end 对应的元素,如果省略 end 将复制 start 之后的所有元素(返回新数组)
  3. let arr2 = arr.concat([1,2,3]); // 将多个数组(也可以是字符串,或者是数组和字符串的混合)连接为一个数组(返回新数组)
  4. console.log(arr) // ["a", "b", "c", "d", "e"]
  5. console.log(arr1) // ["b"]
  6. console.log(arr2) // ["a", "b", "c", "d", "e", 1, 2, 3]

其实sliceconcat也可以作为数组的拷贝方法:

  1. arr.slice(0) // 返回数组的拷贝数组,注意是一个新的数组,不是指向
  2. arr.concat() // 返回数组的拷贝数组,注意是一个新的数组,不是指向

Map

Map是一组键值对的结构,具有极快的查找速度。

创建

方法一: 创建的时候初始化

  1. let mapObj = new Map([
  2. ['a', 1],
  3. ['b', 2],
  4. ['c', 3]
  5. ])
  6. console.log(mapObj.size) // 3

方法二: 创建空Map,之后添加元素

  1. let mapObj = new Map()
  2. mapObj.set('a', 1)
  3. mapObj.set('b', 2)
  4. mapObj.set('c', 3)
  5. console.log(mapObj.size) // 3

注意: Map对象的长度不是length,而是size

基础操作

Map对象的创建、添加元素、删除元素...

  1. mapObj.set('a', 1) // 添加元素
  2. mapObj.delete('d') // 删除指定元素
  3. mapObj.has('a') // true
  4. mapObj.get('a') // 1

遍历

使用上面创建的Map进行操作

forEach

同数组的forEach遍历,三个参数分别代表: value、key、map本身

  1. mapObj.forEach((e, index, self) => {
  2. console.log(index, ' => ', e)
  3. })

打印出:

  1. a => 1
  2. b => 2
  3. c => 3

for-of

  1. for (const e of mapObj) {
  2. console.log(e)
  3. }

打印出:

  1. ["a", 1]
  2. ["b", 2]
  3. ["c", 3]

注意: for-of遍历出来的是一个数组,其中e[0]为key,e[1]为value

Set

Set和Map类似,但set只存储key,且key不重复。

创建

方法一: 创建的时候初始化

  1. let setObj = new Set([1, 2, 3])
  2. console.log(setObj.size)

方法二: 创建空Map,之后添加元素

  1. let setObj = new Set()
  2. setObj.add(1)
  3. setObj.add(2)
  4. setObj.add(3)
  5. console.log(setObj.size)

注意: Map对象的长度不是length,而是size

基础操作

  1. let s = new Set([1, 2, 3])
  2. s.add(3) // 由于key重复,添加不进
  3. s.delete(3) // 删除指定key
  4. console.log(s) // 1 2

遍历

使用上面创建的Set进行操作

forEach

Set与Array类似,但Set没有索引,因此回调函数的前两个参数都是元素本身

  1. s1.forEach(function (element, sameElement, set) {
  2. console.log(element) // element === sameElement
  3. })
  4. // 打印 1 2 3

for-of

  1. for (const item of s1) {
  2. console.log(item)
  3. }
  4. // 打印 1 2 3

类数组对象

JavaScript中,数组是一个特殊的对象,其property名为正整数,且其length属性会随着数组成员的增减而发生变化,同时又从Array构造函数中继承了一些用于进行数组操作的方法。而对于一个普通的对象来说:

如果它的所有property名均为正整数,同时也有相应的length属性,那么虽然该对象并不是由Array构造函数所创建的,它依然呈现出数组的行为,在这种情况下,这些对象被称为“类数组对象”。

形如:

  1. let obj = {
  2. 0: 'qzy',
  3. 1: 22,
  4. 2: false,
  5. length: 3
  6. }

类数组对象可以使用Array对象原生方法进行操作。

遍历

沿用上述对象进行操作

forEach

  1. Array.prototype.forEach.call(obj, function(el, index){
  2. console.log(index, ' => ', el)
  3. })

map

  1. Array.prototype.map.call(obj, function(el, index){
  2. console.log(index, ' => ', el)
  3. })

注意: 类数组对象不支持使用for-of进行遍历,否则会报错: [Symbol.iterator] is not a function

增删截取操作

沿用上述对象进行操作

  1. Array.prototype.join.call(obj, '-') // qzy-22-false
  2. Array.prototype.slice.call(obj, 1, 2) // [22]
  3. Array.prototype.push.call(obj, 5) // Object {0: "qzy", 1: 22, 2: false, 3: 5, length: 4}

String也是一个类数组对象

由于字符串对象也存在length,且序号从0开始增加,因此字符串也可以看做一个只读的类数组对象,这意味着String对象可以使用Array的所有原型方法。

  1. let str = 'hello world'
  2. console.log(Array.prototype.slice.call(str, 0, 5)) // ["h", "e", "l", "l", "o"]

String也可以使用for-of进行遍历

  1. let str = 'hello world'
  2. for (const s of str) {
  3. console.log(s)
  4. }

String独有方法

除了使用Array原型对象的方法,String还包含其他一些自己独有的方法:

与Array使用方法相同的方法

搜索: indexOf()、lastIndexOf()、concat()

转换

toLowerCase()、toUpperCase()

截取

substr(start, len)

substring(start, end)

slice(start, end)

  1. let str = 'hello world'
  2. let ret1 = str.substr(6, 5) // "world"
  3. let ret2 = str.substring(6, 11) // "world"
  4. let ret3 = str.slice(3, 8) // "lo wo"

substring 是以两个参数中较小一个作为起始位置,较大的参数作为结束位置。

slice 是第一参数为起始位置,第二参数为结束位置,如果结束位置小于起始位置返回空字符串

  1. console.log(str.substring(11, 6) === str.substring(6, 11)) // true

接收负数为参数时:

  • slice会将它字符串的长度与对应的负数相加,结果作为参数;
  • substr则仅仅是将第一个参数与字符串长度相加后的结果作为第一个参数;
  • substring则干脆将负参数都直接转换为0。
  1. let str = 'hello world'
  2. let ret1 = str.substr(-5) // "world"
  3. let ret2 = str.substr(-5, 3) // "wor"
  4. let ret3 = str.substring(6, -1) // "hello"
  5. let ret4 = str.slice(6, -1) // "worl"
  6. console.log(ret1 === str.substr(str.length - 5)) // true
  7. console.log(ret2 === str.substr(str.length - 5, 3)) // true
  8. console.log(ret3 === str.substring(6, 0)) // true
  9. console.log(ret4 === str.slice(6, str.length - 1)) // true

正则

  • match()
  • replace()
  • search()
  1. let str = 'hello world'
  2. let ret0 = str.match(/r/) // 非全局搜索,返回匹配的第一个字符串数组(length为1),包括index和input
  3. let ret1 = str.match(/o/g) // 全局搜索,返回匹配的字符串数组,length为搜索到的匹配正则表达式的长度
  4. let ret2 = str.replace(/o/g, 'e') // 全局替换
  5. let ret3 = str.replace(/O/i, 'e') // 不区分大小写,只替换搜索到的第一个字串
  6. let ret4 = str.search(/l/) // 返回搜索到的第一个匹配字串的索引
  7. let ret5 = str.search(/l/g) // 全局无效,同上
  8. console.log(ret0) // ["r", index: 8, input: "hello world"]
  9. console.log(ret1) // ["o", "o"]
  10. console.log(ret2) // "helle werld"
  11. console.log(ret3) // "helle world"
  12. console.log(ret4) // 2
  13. console.log(ret5) // 2
  14. console.log(str) // 不改变源字符串 'hello world'

转化

Map => Object

  1. let mapObj = new Map([ ['a', 1], ['b', 2], ['c', 3] ])
  2. let obj = {}
  3. for (const item of mapObj) {
  4. obj[item[0]] = item[1]
  5. }
  6. console.log(obj)

Set => Array

  1. let setObj = new Set([1, 2, 3])
  2. let arr = []
  3. for (const item of setObj) {
  4. arr.push(item)
  5. }
  6. console.log(arr)

Array => String

arr.join(separator)

  1. ['a', 'b', 'c', 'd', 'e'].join('')
  2. // toLocaleString 、toString 、valueOf:可以看作是join的特殊用法,不常用

String => Array

str.split(separator)

  1. 'hello world'.split(' ') // ["hello", "world"]

JS中集合对象(Array、Map、Set)及类数组对象的使用与对比(转载)的更多相关文章

  1. 如何在JavaScript中手动创建类数组对象

    前言 关于什么是js的类数组对象这里不再赘述.可以参考这个链接,还有这里. js中类数组对象很多,概念简单的讲就是看上去像数组,又不是数组,可以使用数字下标方式访问又没有数组方法. 例: argume ...

  2. js- 类数组对象

    JavaScript中,数组是一个特殊的对象,其property名为正整数,且其length属性会随着数组成员的增减而发生变化,同时又从Array构造函数中继承了一些用于进行数组操作的方法. 而对于一 ...

  3. 什么是“类数组对象”,在jquer中怎样将类数组对象转换为数组对象

    类数组对象的定义: 所谓"类数组对象"就是一个常规的Object对象,如$("div")但它和数组对象非常相似:具备length属性, 并以0.1.2.3……等 ...

  4. 浅谈js的类数组对象arguments

    类数组对象:arguments总所周知,js是一门相当灵活的语言.当我们在js中在调用一个函数的时候,我们经常会给这个函数传递一些参数,js把传入到这个函数的全部参数存储在一个叫做arguments的 ...

  5. [Effective JavaScript 笔记]第58条:区分数组对象和类数组对象

    示例 设想有两个不同类的API.第一个是位向量:有序的位集合 var bits=new BitVector(); bits.enable(4); bits.enable([1,3,8,17]); bi ...

  6. NodeList类数组对象: HTMLCollection , NamedNodeMap,两套API(childNodes , children)

    快捷键:leishuzuduixiang(类数组对象)  bianlijiedian(遍历节点)  jiedian(节点)  htmlcollection , namednodemap , nodel ...

  7. [Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法

    前面有几条都讲过关于Array.prototype的标准方法.这些标准方法被设计成其他对象可复用的方法,即使这些对象并没有继承Array. arguments对象 在22条中提到的函数argument ...

  8. 类数组对象HTMLCollenction

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  9. JS中集合对象(Array、Map、Set)及类数组对象的使用与对比

    原文地址 在使用js编程的时候,常常会用到集合对象,集合对象其实是一种泛型,在js中没有明确的规定其内元素的类型,但在强类型语言譬如Java中泛型强制要求指定类型. ES6引入了iterable类型, ...

随机推荐

  1. Android引用多媒体

    res目录下,创建raw目录(Android会自动识别这个目录),如果自己创建的目录,可能无效底下的mp3格式,mp4格式的文件名必须小写. 引用方式: mediaPlayer = MediaPlay ...

  2. 从头到尾说一次 Java 垃圾回收,写得非常好! (转)

    之前上学的时候有这个一个梗,说在食堂里吃饭,吃完把餐盘端走清理的,是 C++ 程序员,吃完直接就走的,是 Java 程序员.

  3. Linux服务器应急事件溯源报告

    Linux服务器应急事件溯源报告 小博博 · 2016/02/18 17:43 Author:Inn0team 0x00 目录 关于目标环境的中间进度检测报告 一:情况概述 二:取证情况 2.1 目标 ...

  4. vue组件之间通信的8种方式

    对于vue来说,组件之间的消息传递是非常重要的,下面是我对组件之间消息传递的常用方式的总结. props和$emit(常用) $attrs和$listeners 中央事件总线(非父子组件间通信) v- ...

  5. vue.js(1)--创建vue实例的基本结构

    vue实例基本结构与MVVM框架 (1)vue实例基本结构 <!DOCTYPE html> <html lang="en"> <head> &l ...

  6. C/C++ 零碎知识点

    传递参数的一般指导原则: 对于使用传递的值而不做修改的函数: 如果数据对象很小,比如内置类型或者小型结构,按值传递. 如果数据对象是数组,只能使用指针,并将指针生命为指向const的指针. 如果数据对 ...

  7. ARM伪指令和协处理器访问指令

    伪指令本身没有对应的机器码 .global声明全局符号,点事GUN汇编的特点 .data定义数据段 .equ DA #0x89 定义宏 .align 4 4字节对齐 mov 指令里的立即数只能是8位的 ...

  8. ceph对接openstack

    一.使用rbd方式提供存储如下数据: (1)image(glance):保存glanc中的image: (2)volume(cinder)存储:保存cinder的volume:保存创建虚拟机时选择创建 ...

  9. zabbix 内存溢出

    tail -f /var/log/zabbix/zabbix_server_log ::165110.914 ================================ ::165110.914 ...

  10. 011-通过安装percona插件监控MySQL

    percona-monitoring-plugins是percona专门为MySQL监控的工具,支持Nagios,cacti,zabibx,本文主要介绍percona-monitoring-plugi ...