一文带你彻底搞懂JS中的Map与Set

 更新时间:2023年11月30日 08:36:18   作者:Hyyy  
Set是一种叫做集合的数据结构(结构和Array很像),Map是一种叫做字典的数据结构,这篇文章主要为大家详细介绍了JavaScript中Map与Set用法与区别,需要的小伙伴可以参考下

定义

Set是一种叫做集合的数据结构(结构和Array很像),Set中的元素是唯一的,即没有重复的(这点很重要)

Map是一种叫做字典的数据结构,和Object一样保存键值对,但Map中键的范围不限于字符串类型,各种类型的值(包括对象)都可以当做是一个键或一个值

Set

Set 本身是一个构造函数,用来生成 Set 数据结构

 let set = new Set();
 console.log(set);  // {}

Set 对象可以存储任意类型的值,但是用Set 构造函数传入的参数只能是可迭代对象,如:数组、字符串

 // 当你传入一个整数时,js会告诉你传入的参数1不是可迭代对象
 let set = new Set(1);
 console.log(set); // number 1 is not iterable
  // 传入对象会报错
 let set = new Set({});
 console.log(set); // object is not iterable
 // 必须是数组或字符串,
 let set1 = new Set('1');
 console.log(set1);
 let set2 = new Set([1, 'true']);
 console.log(set2);

常见的方法

方法说明示例
has()判断是否有该值,返回布尔值set.has('name')
add()向Set()添加元素,若有相同会覆盖set.add('name', 'zxc')
delete用于删除某个元素,成功则返回true,失败返回falseset.deldect('name')
clear()用于清空 Set() 中所有的成员,没有返回值set.clear()
size 属性判断 Set() 有多少个元素set.size
 let set = new Set()
 let arr = [1, 2]
 set.add(1).add(arr)
 set.add(function() { console.log(123); })
 set.add({})
 console.log(set); // { 1, [ 1, 2 ], [Function (anonymous)], {} }
 
 // has() 判断元素
 console.log(set.has(arr));  // true
 
 // size 判断长度
 console.log(set.size);  // 4
 
 // delete 删除
 console.log(set.delete(1)); // true
 console.log(set.delete(arr)); // true,set中存储的对象,只能删除这种有明确地址索引的,不然只能用clear()
 
 // clear 清除
 set.clear()
 console.log(set);  // {}

顺序与迭代

Set() 结构有四个遍历的方法

方法说明示例
keys()返回键的遍历器set.keys()
values()返回值的遍历器set.values()
entries()返回所有成员的遍历器,包含键,值set.entries()
forEach遍历Set的所有成员set.forEach(function(), [this])

由于Set结构没有键名,所以其键名和键值是一致的

 let set = new Set(['张三', '李四', '王五', 'true']);
 // 遍历键 
 console.log(set.keys());  // { '张三', '李四', '王五', 'true' }
 // 遍历值
 console.log(set.values());  // { '张三', '李四', '王五', 'true' }
 // 返回键值
 console.log(set.entries());
 /* {
   [ '张三', '张三' ],
   [ '李四', '李四' ],
   [ '王五', '王五' ],
   [ 'true', 'true' ]
 }*/
 ​
 // forEach() 循环
 let set = new Set(['张三', '李四', '王五', 'true'])
 set.forEach(function(value, key) {
     console.log(key + ':' + value);
 })
 /*
 张三:张三
 李四:李四
 王五:王五
 true:tru*/

也可以使用 for...of 或 for...in

 // 遍历值
 for (let value of set) { console.log(value);}
 // 遍历键
 for (let key in set) {console.log(key);}

类型转换

Set 类型可以与其它类型的值进行转换

Array 转换为 Set

 let arr = [1, 2, 3, 4]
 let set = new Set(arr)
 console.log(set);  // { 1, 2, 3, 4 }

Set 转换为 Array:可以通过扩展运算符 ... 来实现

 let set = new Set([1, 2, 3, 4])
 console.log([...set]);  // [ 1, 2, 3, 4 ]

String 转换为 Set

 let str = '张三'
 let set = new Set(str)
 console.log(set); // { '张', '三' }

Set 的作用

去重

利用Set不重复性可以用于数组的去重

 // 将数组转换为Set,再将Set转换为数组
 let arr = [1, 1, 4, 1, 2, 3, 1, 2]
 let set = new Set(arr)
 console.log([...set]); // [ 1, 4, 2, 3 ]

并集

 let arr1 = [1, 1, 4, '1', 2, 3]
 let arr2 = [5, 1, '2']
 let set = new Set([...arr1, ...arr2])
 console.log([...set]); // [ 1, 4, '1', 2, 3, 5, '2' ]

PS:Set 不允许强制转换,1 和 ‘1’ 被认为是不同的值

Set总结

  • Set 最大的特点就是它的元素是唯一的,基于这个特性可以用于去重
  • Set 可以存储任意类型的值,但是初始化的时候只能传入可迭代对象
  • Set 可以与Array 进行互相转换,也可以把 String 转换为 Set类型
  • 扩展运算符和 Set 结构相结合实现数组或字符串去重

Map

在ES6以前,在js中实现 键/值式 存储可以使用 Object 来高效完成,ES6新增了一种新的集合类型 Map

它最大的特点就是:Map中键的范围不限于字符串类型,各种类型的值(包括对象)都可以当做是一个键或一个值

所以Object 和 Map 键值类型:

  • Object字符串/Symbol类型: 任意类型
  • Map: 任意类型: 任意类型

初始化Map

创建一个空map

 // 必须是以这种方式创建
 let map= new Map();

Map构造函数传入一个可迭代对象,需要包含键值对,每个键值对会按照迭代顺序映射到实例当中

 const map = new Map([
     ['name', 'cyf'],
     ['age', 18]
 ]);
 console.log(map);  // {"name" => "zxc", "age" => 18}

Map常用方法

方法说明示例
get()通过键来获取值,如果没有该键,则返回 undefinedmap.get('name')
has()判断是否有该键,返回布尔值map.get('name')
set()用于设置对应的键值对,若有相同会覆盖map.set('name', 'zxc')
delete()用于删除某个键,成功则返回true,失败返回falsemap.deldect('name')
clear()用于清空 Map() 中所有的成员,没有返回值map.clear()
 let map = new Map([
     ['namer', '张三'],
     ['age', 2]
 ]);
 ​
 // 获取namer
 console.log(map.get('namer')); // 张三
 ​
 // 判断namer
 console.log(map.has('age')); // 2
 ​
 // 设置键值对
 console.log(map.set('sex', '其它')); // { 'namer' => '张三', 'age' => 2, 'sex' => '其它' }
// 可连续设置
 console.log(map.set('id', 0).set('hobby', '讲段子'));
 ​
 // size属性,获取map长度
 console.log(map.size); // 5
 ​
 // 删除某个键
 console.log(map.delete('id')); // true
 ​
 // 清空map
 map.clear()
 console.log(map); // {}

一个key只能对应一个value,多次对一个key放入value,之前的值会被覆盖

let map =new Map()
map.set('Amy',"女")
map.set('Amy',"男")
console.log(map) 

顺序与迭代

与 Object 类型的一个差异是:Map 实例会维护键值对的插入顺序,因此可以根据顺序执行迭代操作

Map 提供了3个遍历器和一个遍历方法

方法说明示例
keys()返回键的遍历器map.keys()
values()返回值的遍历器map.values()
entries()返回所有成员的遍历器,包含键,值map.entries()
forEach遍历Map的所有成员map.forEach(function(), [this])
 let map = new Map().set('namer', '张三').set('age', 2).set('sex', '其它')
 ​
 // 获取键
 let keys = map.keys()
 console.log(keys);
 ​
 // 获取值
 let values = map.values()
 console.log(values);
 ​
 // 获取键值对
 console.log(map.entries());  // { [ 'namer', '张三' ], [ 'age', 2 ], [ 'sex', '其它' ] }
 ​
 for (let [key, value] of map) {
     console.log(key + ':' + value);
 }
 // namer:张三
 // age:2
 // sex:其它
 ​
 // forEach 循环
 map.forEach(function(value, index) {
     console.log(index + ':' + value);
 })
 ​
 // namer:张三
 // age:2
 // sex:其它

Map与Object的区别

键名类型

  • Object 只能接收两种类型的键名:String 和 Symbol
  • Map 能够接受任意类型的键名

Map 键名:

 let map = new Map();
 map.set(1, 'Number').set(true, 'Boolean').set({ '键名': '键值' }, 'Object').set(function() {}, 'Function')
 console.log(map);  
 // { 1 => 'Number', true => 'Boolean', { '键名': '键值' } => 'Object', [Function (anonymous)] => 'Function'}

Object键名

 let obj = {}
 obj[1] = 'Number';
 obj[true] = 'Boolean';
 obj[{ '键名': '键值' }] = 'Object';
 obj[function() {}] = 'Function'
 ​
 console.log(obj);
 // { '1': 'Number', true: 'Boolean', '[object Object]': 'Object', 'function() {}': 'Function' }

虽然说Object 可以接受其他类型的键名,当时js都会隐式地将其转换为字符串

迭代

  • Map 是可以迭代的,用 forEach循环或 for...of
  • Object 是不能直接进行迭代的

Object 遍历需要借助对象的静态方法

 let obj = { 'namer': '张三', 'age': 2, 'sex': '其它' }
 ​
 // 遍历键
 for (let key of Object.keys(obj)) {
     console.log(key);
 }

还可以是:

 for (let value of Object.values(obj)) {}
 ​
 for (let keyValue of Object.entries(obj)) {}
 ​
 for (let [key, value] of Object.entries(obj)) {}

当然可以使用 for...in 遍历键

 for (let key in obj) {
     console.log(key); // namer age sex
 }

顺序和长度

长度

  • Map保存对长度的跟踪,可直接使用size,其时间事件复杂度为 O(1)
  • 对于 Object而言,想要获取对象长度需要对于其进行迭代,其时间复杂度为 O(n)

顺序

  • Map 始终是保持键值对插入时的顺序
  • Object则不是,不过ES6之后就会可以按顺序保存了,只是通过隐式转换为字符串的键就乱序了

总结

  • Map的键可以是任意类型,并且可以用 forEach 等迭代
  • Map 的键值对是根据set设置的顺序存储的
  • Map 获取长度就是用size属性直接返回,时间复杂度为 O(1)
  • Map 缺点就是不能使用 [] 和  来设置和获取键值,只能用set 和 get 来替换
  • 固定大小内存,Map 大约可以比Object 多存储50%的键值对

WeakSet 和 WeakMap

WeakSet

WeakSet 是一种 “弱集合”类型,其集合中的值只能是对象

由于Set结构没有键名,所以其键名和键值是一致的

 let set = new Set(['张三', '李四', '王五', 'true'])
方法说明
has()判断是否有该值,返回布尔值
add()向Set()添加元素,若有相同会覆盖
delete()用于删除某个元素,成功则返回 true,失败返回 false

1、创建一个空的WeakSet

 let WeakSet = new WeakSet();

2、初始化WeakSet

构造函数可以传入一个迭代对象,可迭代对象中的值必须得是对象

 let x = { id: 1 },
     y = { id: 2 }
 let weakSet = new WeakSet([x, y]);
 console.log(weakSet);
 ​
 console.log(weakSet.has(x)); // true
 console.log(weakSet.delete(x)); // true 

WeakSet 中没有clear方法 和 size属性

因为 WeakSet 中的值任何时候都可能被销毁,所以没必要提供迭代的功能,也用不着先clear这个清空的功能

另外,因为 WeakSet 的成员可以被垃圾回收机制回收,所以可以用来保存DOM节点,不容易造成内存泄露

WeakMap

weakMap 是 Map的变体,它们的方法基本是一样的,区别在于内部分配的工作方式

weakMap 只接受引用类型的数据作为键名,如:数组、函数、对象等

1、创建一个空的WeakMap

 let WeakMap = new WeakMap();

2、初始化WeakMap

 let weakMap = new WeakMap();
 let x = { id: 1 },
     y = { id: 2 }
 weakMap.set(x, '张三')
 weakMap.set(y, 2)
 
 console.log(weakMap.get(x)); // 张三
 console.log(weakMap.get(y)); // 2
 
 console.log(weakMap.has(x)); // true
 console.log(weakMap.delete(x));  // true

WeakMap 中没有clear方法 和 size属性

到此这篇关于一文带你彻底搞懂JS中的Map与Set的文章就介绍到这了,更多相关JS Map Set内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论