Array, Set, Map知多少?
Array,Set和Map三个作为Javascript中可迭代的集合数据类型,在编程过程中使用的频率也比较高。针对三种数据类型各自的一些特性,本文的内容将从以下几个方面来上述数据类型做一个总结。
实例的创建
Map和Set创建实例的方式是唯一的,只允许通过new调用构造方法来创建一个实例。值得注意的是,Set和Map在调用构造函数的时候,传参都是数组或者可迭代对象,其中Map的传参数组需要时一个键值对数组。当然,传参也是可选的,非必须。
Array相较于前两者,其创建实例的方式要多写,可通过字面方式创建,也可像Map和Set一样通过构造函数来创建。此外使用Array的静态函数Array.from来创建也是非常常见的。例如,通过docuemnt.getElementsByTagName这类方法获取到一个HTMLCollect这样一个类数组,通常会通过Array.from将其装换成一个真正的数组来进行后续的操作。
// 创建map实例
let map1 = new Map();
let map2 = new Map([['a', 1], ['b', 2]]); // a=>1, b=>2
// 创建set实例
let set1 = new Set();
let set2 = new Set([1,2])
// 通过字面量创建数组
let arr1 = [1,2,3];
// 使用Array静态方法从一个可迭代对象或者类数组中创建数组实例
let arr2 = Array.from([4,5])
// 使用Array构造函数
let arr3 = new Array([6,7]);
数据添加与变更
// Set的数据操作:添加与删除
let set = new Set();
set.add(11) // [11]
set.add(23) // [11, 23]
set.add(11) // [11, 23]
set.delete(23) // [11]
// Map的数据操作:添加与删除
let map = new Map();
map.set('a', 1); // [a=>1]
map.set('b', 2); // [a=>1, b=>2]
map.delete('b'); // [a=>1]
// Array
let arr = [1,2,3]
// 在数组末尾添加一个值
arr.push(4) // [1,2,3,4]
// 弹出数组末尾的值
arr.pop(4) // [1,2,3]
// 在数组头部添加一个值
arr.unshift(0) // [0,1,2,3]
// 移除头部的第一个值
arr.shift() // [1,2,3]
// 在第二个数(下标1)之后插入一个值‘a’
arr.splice(1,0,'a') // [1,2,'a', 3];
// 删除第二个数(下标1)后面1个值,然后插入一个新的值‘b’
arr.splice(1,1,'b') // [1,2,'b',3]
数据访问
Array和Map都能够访问实例中的特定数据,Array是通过下标,而Map是通过实例方法get, 唯独Set没有方式可以直接访问其中特定数据。其实也不难理解,Set本身不是为了单纯存储数据和访问特殊而生的,因为这些功能Array就可以支持,何必再单出构造一个Set数据结构了。我对此的理解是,Set跟多的是紧紧围绕着数据唯一不重复这一准则来的,它的侧重点是某一数据的有无,而不是数据存在哪里。
另外,从结构上来说。Set不像Array那样是有序的,所以也无法使用下标来访问,也不像Map那般,每个键对应一个值,所以也无法通过键来访问。故而,Set没有单独访问某一数据的方式。
const arr = [1,2,3];
const set = new Set(['a', 'b']);
const map = new Map([['a', 1], ['b', '2']]);
//Array通过下标访问数据
console.log(arr[0], arr[2]) // 1, 3
//Map使用实例方法get访问数据,参数是键
console.log(mpa.get('a)) // 1
数据的遍历
Set数据的遍历方式:
- keys() 返回键名迭代器
- values() 返回值迭代器
- entries() 返回键值迭代器
- forEach()
const set = new Set(['a', 'b', 'c']);
// set每个值对应的key其实也是数据值本身
const keyIter = set.keys();
console.log(keyIter.next().value); // 'a'
console.log(keyIter.next().value); // 'b'
console.log(keyIter.next().value); // 'c'
console.log(keyIter.next().value); // undefined
const valueIter = set.values();
for(let val of valueIter) {
console.log(val); // 'a', 'b', 'c'
}
const entriesIter = set.entries();
for(let [key, value] of entriesIter) {
console(`${key}:${value}`) // 'a':'a', 'b':'b', 'c':'c'
}
set.forEach(val => {
console.log(val) // 'a', 'b', 'c'
})
Map数据的遍历方式
- keys() 返回键名迭代器
- values() 返回值迭代器
- entries() 返回键值迭代器
- forEach()
const map = new Map([['a', 1], ['b', '2']]);
/**
* 代码就自己脑补吧,
* 不能说和Set的方式很像,
* 只能说真的就是一模一样
**/
Array数据的遍历方式
Array遍历数据的方法是最多的,除了下面列举的几个之外,还有some, every,甚至filter, find和findIndex这些方法可以用来遍历数据。使用这些方法需要注意的是其使用的场景,例如map和forEach都可以用来对数组内数据做一些操作,但如果不需要返回值的情况,还是使用forEach方法,而不建议是map,其它方法也是如此。
- keys() 返回键名迭代器
- values() 返回值迭代器
- entries() 返回键值迭代器
- map() 回调函数,要有返回值
- reduce()
- forEach()
- for...of
/**
* 代码就不写了,偷个懒,不过还是贴心的附上链接
* https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array
**/
类似的功能和一些专有方法
- 是否包含某个元素: 数组的includes方法,map和set的has方法,三者的返回值都是布尔值,区别只在于传入的参数。数组和set传入的是值,map传入的是键。
- 合并两个相同类型的数据: 数组使用concat方法,合并两个数组值,set使用union方法合并两个集合。map没有专有方法可以用来合并两个map数据,不过可以通过使用new Map([...map1, ...map2])来返回一个合并之后的新map
- 数据大小:数组有length属性,map和set有size属性
- 清空数据:map和size都可通过clear()方法来清空数据,数组无专有方法,可自己通过修改length值为0或者使用splice方法清空数据。
关于数组中的includes方法在数组值为一个个对象的时候,这个时候传入的值就只能是对象的引用了。如果作用域内不存在引用的话,判断数组中是否存在某个对象,就只能通过filter, find或者findIndex之类的方法加上数据特征去判断数组中是否存在该对象了。
三者之间的转换
const arr = [1, 3, 4, 4];
const arr1 = [['a', 'Kebei']];
const map = new Map(['a', 1], ['b', 2]);
const set = new Set([1, 5]);
// Array 转 Set
const arr2Set = new Set(arr); // [1, 3, 4];
// Array 转Map
const arr2Map = new Map(arr1); // {'a' => 'Kebei'}
//Set转Array
const set2Arr = Array.from(set); // [1, 5]
const set2Arr2 = [...set]; // [1, 5]
const set2Arr3 = set.values() // [1, 5]
//Set转Map
const set2Map = new Map(set.entries()) // { 1=> 1, 5=>5}
// Map转Array
const map2Arr = Array.from(map); // ['a', 1], ['b', 2]
const map2Arr2 = [...map]; // ['a', 1], ['b', 2]
const map2Arr3 = map.values() // ['a', 1], ['b', 2]
// Map转Set
const map2Set = new Set(map.values()) // [1, 2]
应用场景
最常见的一种场景莫过于使用数组与Set之间格式变化进行数据去重
const dedup = (arr) => {
return [...new Set(arr)]
}
上述方法和之前includes方法也是一样存在无法处理复杂数据类型,对于复杂对象数据,需要根据各自业务场景对重复的数据进行去重策略选择,即在一堆的重复对象中(以id重复为例)保留业务需要的唯一一个数据。
总结
三种数据结构有着各自不同的特性。数组是一个天然的栈,也是一个天然的队列,在三种数据结构中,其实例方法也应用也是最多的,是线性存储中话事人般的存在,也是我们在普通业务场景下的首选。Set数据的唯一性,可以帮助我们在业务场景中快速的进行去重。Map键值对结构的特殊性,以及对键的包容性,能够通过键快速获取到值,也是复杂业务冲常常用的。
【资料参考】
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
Array, Set, Map知多少?的更多相关文章
- 003-Tuple、Array、Map与文件操作入门实战
003-Tuple.Array.Map与文件操作入门实战 Tuple 各个元素可以类型不同 注意索引的方式 下标从1开始 灵活 Array 注意for循环的until用法 数组的索引方式 上面的for ...
- Array(数组)--map方法
关于Array.prototype.map() MDN 给的定义是: 在作用数组元素的每一项上调用一个方法(callback),返回一个新数组: 使用格式:arr.map(callback[,this ...
- Javascript中Array.prototype.map()详解
map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数.callback 每次执行后的返回值组合起来形成一个新数组. callback 函数只会在有值的索引上被调用:那些从来没被赋 ...
- Array.prototype.map()详解
今天在地铁上看到这样一个小例子: ["1","2","3"].map(parseInt); 相信很多人和我一样,觉得输出的结果是[1,2,3 ...
- Array.prototype.map()
mdn上解释的特别详细 概述 map() 方法返回一个由原数组中的每个元素调用一个指定方法后的返回值组成的新数组. 语法 array.map(callback[, thisArg]) 参数 callb ...
- Scala学习笔记之:tuple、array、Map
[TOC] 本文<快学Scala>的笔记 tuple学习笔记 tuple的定义 对偶是元组(tuple)的最简单形态--元组是不同类型的值的聚集. 元组的值是通过将单个值包含在圆括号中构成 ...
- 深入理解 Array.prototype.map()
深入理解 Array.prototype.map() map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果. 语法 let new_array = arr.map ...
- JS中集合对象(Array、Map、Set)及类数组对象的使用与对比
原文地址 在使用js编程的时候,常常会用到集合对象,集合对象其实是一种泛型,在js中没有明确的规定其内元素的类型,但在强类型语言譬如Java中泛型强制要求指定类型. ES6引入了iterable类型, ...
- Array.prototype.map()和Array.prototypefilter()
ES5 => 筛选功能 Array.prototypefilter(): 代码: var words = ['spray', 'limit', 'elite', 'exuberant', 'd ...
- hive中array嵌套map以及行转列的使用
1. 数据源信息 {"student": {"name":"king","age":11,"sex" ...
随机推荐
- swoole(7)php进程间通信-消息队列
php实现消息队列操作 ftok:可以将一个路径转换成消息队列可用的key值 msg_get_queue:第一个参数是消息队列的key 第二个参数是消息队列的读写权限 server代码: <?p ...
- https证书中的subject alternative name字段作用及如何生成含该字段的证书
背景 最近,某个运维同事找到我,说测试环境的某个域名(他也在负责维护),假设域名为test.baidu.com,以前呢,证书都是用的生产的证书,最近不让用了.问为啥呢,说不安全,现在在整改了,因为证书 ...
- Go Module使用 六大场景讲解示例
前言 通过学习Go是怎么解决包依赖管理问题的?.go module基本使用,我们掌握了 Go Module 构建模式的基本概念和工作原理,也初步学会了如何通过 go mod 命令,将一个 Go 项目转 ...
- Go语言计算字符串长度——len()和RuneCountInString()
Go 语言的内建函数 len(),可以用来获取切片.字符串.通道(channel)等的长度.下面的代码可以用 len() 来获取字符串的长度. tip1 := "genji is a nin ...
- Linux 实现OpenSSL 服务器端客户端通信
1.OpenSSL安装 详情参考博文:https://blog.csdn.net/qq_39521181/article/details/96457673 2.SSL 在学习openssl编程之前,先 ...
- apisix~key-auth多消费的使用
在 APISIX 中使用 key-auth 插件实现基于密钥的认证,以下是详细的配置步骤,包括如何保存密钥和证书,以及如何将这些信息分配给客户端 A 和 B. 场景说明 服务 C 是后端服务,需要通过 ...
- 【C#】Winform嵌入dll到exe中
[C#]Winform嵌入dll到exe中 零.问题 最近在做一个上位机,需要保存数据,所以引用了一些Excel的组件,但是比较麻烦的是会多出几个DLL文件,压缩打包不方便使用,于是想能不能嵌入到ex ...
- Ant Design Pro 中 点击子菜单的时候,其他菜单不自动收起来
记录一波自己在这段时间碰到的一个Ant Design Pro 的坑: 每次点击菜单都会将其他菜单自动收起来,导致一系列的用户体验不佳. 设置defaultOpenAll: true后依然不管用 经过各 ...
- 第八届机械工程与应用复合材料国际会议(MEACM 2025)
第八届机械工程与应用复合材料国际会议(MEACM 2025) 吉隆坡,马来西亚 2025年8月25-27日 会议简介:2025年第八届机械工程与应用复合材料国际会议(MEACM 2025)将于2025 ...
- ESP32系列,IDF官方实例——外设:通用GPIO
示例位于 \examples\peripherals\gpio\generic_gpio 文件夹内 GPIO示例逻辑简单,直接看代码理解. /* GPIO示例 此示例代码位于公共域(或CC0许可,由您 ...