ES6学习笔记(10)----Set和Map数据结构
参考书《ECMAScript 6入门》
http://es6.ruanyifeng.com/
Set和Map数据结构
1.Set
基本用法
Set是一种新的数据结构,它的成员都是唯一的不重复的。
let s1 = new Set();
s1.add({"name":"123"});
s1 // Set(1){{"name":"123"}}
let s2 = new Set([1,2,3,4,4,3,2,1]);
s2 //Set(4) {1, 2, 3, 4}
Set判断重复的方式是精准相等,同Object.is()
NaN == NaN //false
NaN === NaN //false
Object.is(NaN,NaN)//true
let s3 = new Set();
s3.add(NaN);
s3.add(NaN);
s3 //Set(1) {NaN} //Set添加的成员都是不重复的
Object.is({},{});//false 两个空对象总是不相等
s3.add({});
s3.add({});
s3 //Set(3) {NaN, {}, {}}
Set实例的属性和方法
属性
Set.prototype.constructor:返回set结构的构造器 ƒ Set() { [native code] }
Set.prototype.size:返回set存储数据的大小
方法
add:向set结构中添加成员
has:判断set中是否有某个成员
delete:删除set中的某个成员
clear:清楚set中的所有成员
let s1 = new Set();
s1.add({"test":"11"});
s1.add({"test":"22"});
s1//Set(2) {{"test":"11"}, {"test":"22"}}
s1.has("test");//false
s1.delete("test");//false
s1.has({"test":"11"});//false
s1.delete({"test":"11"});//false
let s2 = new Set();
s2.add("name");
s2.has("name");//true
对象与Set解构判断是否含有某一个key值的不同方式
var obj = {
name : "test",
value : "123"
}
obj.name//"test"
obj[name]//"test"
obj.value//"123"
obj[value]//"123"
let s4 = new Set();
s4.add("name");
s4.add("value");
s4.has("name");//true
遍历操作
(1)数组结构,对象结构,set结构调用keys(),values(),entries()遍历比较
数组结构
let arr = [1,2,3,4,5];
for(let k of arr.keys()){
console.log(k);//0 1 2 3 4
}
for(let v of arr.values()){
console.log(v);//1 2 3 4 5
}
for(let entry of arr.entries()){
console.log(entry);//[0,1] [1,2] [2,3] [3,4] [4,5]
}
对象结构
let obj = {
name : "test",
size : 13,
color : "red"
}
for(let k of Object.keys(obj)){
console.log(k);//name size color
}
for(let v of Object.values(obj)){
console.log(v);//test 13 red
}
for(let o of Object.entries(obj)){
console.log(o);//["name", "test"] ["size", 13] ["color", "red"]
}
Set 结构:set结构没有键名,只有键值,所以keys和valus方法返回值一致,entries每次调用返回的是一个数组,数组成员是这个entry的键名和键值,所以两个数组成员是相等的
let s = new Set();
s.add({name : "test"});
s.add({age : 13});
s.add({color :"red"});
for(let k of s.keys()){
console.log(k);//{name: "test"} {age: 13} {color: "red"}
}
for(let v of s.values()){
console.log(v);//{name: "test"} {age: 13} {color: "red"}
}
for(let o of s.entries()){
console.log(o);//[{name: "test"}, {name: "test"}] [{age: 13},{age: 13}] [{color: "red"},{color: "red"}]
}
for(let v of s){
console.log(v);//{name: "test"} {age: 13} {color: "red"} Set结构的实例默认是可遍历的,默认遍历器是values()方法
}
(2)数组结构与set结构调用forEach()遍历比较
数组结构
let arr = [1,2,3,4,5];
arr.forEach(function(i,v){
v = v + 2;
console.log(v);
});// 2 3 4 5 6
arr.forEach((i,v) => console.log(v*5));//0 5 10 15 20
Set结构
let s = new Set([1,2,3,4,5]);
s.forEach(function(i,v){
console.log(v - 1);
});//0 1 2 3 4
等同于
s.forEach((i,v) => console.log(v - 1););//0 1 2 3 4
遍历的应用
扩展运算符(...)内部使用for...of循环,因此set结构也可以使用
let s = new Set();
s.add({name : "test"});
s.add({age : 13});
s.add({color :"red"});
[...s] //[{name : "test"}, {age : 13}, {color :"red"}]
目前可以使用扩展运算符(...)的结构:Array,Object,Set
数组的map和filter也可以间接用在Set结构上
let s = new Set([1,2,3,4,5]);
s = new Set([...s].map(x => x+2));//Set(5) {3, 4, 5, 6, 7}
s = new Set([...s].filter(x => (x%2) === 0));//Set(2) {2, 4}
使用Set实现交集,并集,差集
let s1 = new Set([1,2,3,4,5]);
let s2 = new Set([3,4,5,6,7]);
并集
let s3 = new Set([...s1,...s2]);
s3 //Set(7) {1, 2, 3, 4, 5, 6, 7}
交集
let s4 = new Set([...s1].filter(x => s2.has(x)))
s4 //Set(3) {3, 4, 5}
差集
let s5 = new Set([...s1].filter(x => !s2.has(x)))
s5 //Set(2) {1, 2}
2.WeakSet
含义:WeakSet和Set一样都是不可重复的数据结构,但是WeakSet的成员只能是对象
let s1 = new Set();
s1.add(3);
s1.add({name : "test"});
s1 //Set(2) {3, {name : "test"}}
let s2 = new WeakSet();
s2.add({name : "test"});
s2 //WeakSet {{name : "test"}}
s2.add(3);//Uncaught TypeError: Invalid value used in weak set 只能接受加入对象成员
WeakSet中的对象都是弱引用,如果其他地方没有引用这个对象,垃圾回收机制就会自动回收该对象所占用的内存,不考虑对象还存在于WeakSet中
语法
let w1 = new WeakSet();
w1.add({name : "test"});
除对象外,数组以及类数组都可以添加到weakSet结构中
let dd = document.querySelectorAll("tr");
w1.add(dd);
w1.add([1,2]);
w1 //WeakSet {{name : "test"},NodeList(626), [1,2]}
let a = [3,4];
w1.add(a);//WeakSet {{name : "test"},NodeList(626), [1,2],[3,4]}
let w2 = new WeakSet(a);
//Uncaught TypeError: Invalid value used in weak set
//此处数组a的成员是单个数值,不是对象,调用WeakSet构造器生成WeakSet结构时,被加入到WeakSet中的是数组的成员,由于成员不是对象,所以报错
WeakSet结构有三个方法add,has和delete
WeakSet.prototype.add:向WeakSet结构中添加一个新成员
WeakSet.prototype.has:返回一个布尔值,表示某一个值是否存在WeakSet实例当中
WeakSet.prototype.delete:清除WeakSet实例的指定成员
w1.add(window);
w1.has(window);//true
w1.delete(window);//true
WeakSet没有size属性,不能遍历,因为它的成员都是弱引用,随时可能消失。
数组去重的方法
(1)Set结构与扩展运算符(...)相结合
let arr = [1,2,3,4,3,2,'a','aa','b','a'];
[...new Set(arr)] //[1, 2, 3, 4, "a", "aa", "b"]
3.Map
含义:Map是一种键值对构成的数据结构,不同于对象,map的键可以是任何简单值或者对象。
基本用法
set:set(key,value) 向Map结构中添加键值对。返回值map因此可以链式调用
get:get(key) 读取Map结构中键值为key所对应的value值
has:has(key) 判断Map结构中是否含有键值为key的键值对,返回值是布尔类型
delete:delete(key) 删除Map结构中键值为key所对应的键值对
clear:map.clear() 清除map结构实例的所有成员
生成Map实例的方法
(1)先用new Map构造器的方式生成map结构,再使用基本方法将数据添加到Map结构中
let m1 = new Map();
m1.set(0,"t1");
m1.set({name : "maptest"},"test2");
m1.set("color",2);
m1.get({name : "maptest"});//undefined
//{name : "maptest"} == {name : "maptest"} false {name : "maptest"} === {name : "maptest"} false Object.is({name : "maptest"},{name : "maptest"})
//虽然看起来值相同,但是{name : "maptest"} == {name : "maptest"} 左右两个对象是不同的内存地址,所以是两个对象
//'color' === 'color' true ['color'] === ['color'] false
let obj = {name : "maptest"};
m1.set(obj,"t3");
m1.get(obj);// "t3"
m1.has(0);//true
m1.delete('color');//true
m1.has('color');//false
(2)使用new Map构造器创建map实例时,
将有iterator迭代器接口的数据结构,并且此结构成员是一个双成员的数组,传入构造器中做参数
有iterator迭代器接口的结构如数组,类数组对象,set,map
数组
let m2 = new Map([["name","value"]]);
m2 //Map(1) {"name" => "value"}
m2.get("name");//"value"
类数组对象
let divArr = document.querySelectorAll("tr");
let arr = [];
function test(){
[...divArr].forEach(function(value,index){
arr.push([index,value]);
});
}
test();
arr //[[0, NodeList(69)]]
let m3 = new Map(arr);
m3.get(0);//NodeList(69) [n1,n2,n3......]
Set数据结构
let s1 = new Set([[1,10],[2,20]]);
let m4 = new Map(s1);
m4.get(1);//10
m4.has(2);//true
Map数据结构
let m5 = new Map([["run","fast"]]);
let m6 = new Map(m5);
m6.get("run");//"fast"
如果针对同一个键重复赋值,则后赋的值会代替先赋的值
m6.set("run","slow");
m6.get("run");//"slow"
Map的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个值。
'a' === 'a' true 简单值严格相等,map视为同一个值
['a'] === ['a'] false 内存地址不同,map视为不同的值
实例的属性和操作方法
属性
size:返回Map结构的成员总数
方法
set/get/has/delete/clear
遍历方法
keys()/values()/entries()/forEach()用法同set,遍历顺序即插入顺序。
let m = new Map();
m.set(name,"test");
m.set(age,13);
m.set(color,"red");
for(let k of m.keys()){
console.log(k);//name age color
}
for(let v of m.values()){
console.log(v);//test 13 red
}
for(let o of m.entries()){
console.log(o);//["name": "test"] ["age": 13] ["color": "red"]
}
for(let v of m){
console.log(v);//["name": "test"] ["age": 13] ["color": "red"] map结构的实例默认是可遍历的,默认遍历器是entries()方法
}
m.forEach(function(v,i){
console.log("key : "+i+",value : "+v);
});
//key : name,value : test
//key : age,value : 13
//key : color,value : red
m.forEach(function(v,i){
console.log(navigator.userAgent);
},navigator);
//3 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
//forEach除了回调函数还可以传第二个参数,可以用来绑定对象
Map与其他数据结构互相转换
let m = new Map();
m.set(name,"test");
m.set(age,13);
m.set(color,"red");
(1)Map与数组互相转换
a.(...)扩展运算符可以将map转换成数组
console.log([...m]);//[["name": "test"],["age": 13],["color": "red"]]
b.通过将符合标准的数组传入map构造器中生成map实例,可以实现数组转换成map结构
let arr = [[0,'a'],[1,'b'],[2,'c']];
let m = new Map(arr);
m //Map(3) {0 => "a", 1 => "b", 2 => "c"}
(2)Map与对象互相转换
a.通过循环遍历将map的key值赋值给对象的属性名,value值赋值给对象的属性值,可以实现map转换成对象。
let m = new Map([[{color : "black"},"22"]]).set(0,'test').set(1,'a');
m //Map(3) {{color: "black"} => "22", 0 => "test", 1 => "a"}
let obj = {};
for(let [k,v] of m){
obj[k] = v;
}
obj //{0: "test", 1: "a", [object Object]: "22"}
//{color: "black"} 这个键名是非字符串的,所以被转化成了[oject object]
b.对象转换成map 遍历对象,将对象的属性名设置成map的key值,将对象的属性值设置成map的value值
let obj = {0: "test", 1: "a", 2: "22"}
let m = new Map(Object.entries(obj));
m //Map(3) {"0" => "test", "1" => "a", "2" => "22"}
(3)Map与JSON互相转换
a.可以通过map-->Array-->json或map-->Object-->json的两种方式实现map转换成json
let m = new Map([[{color : "black"},"22"]]).set(0,'test').set(1,'a');
m //Map(3) {{color: "black"} => "22", 0 => "test", 1 => "a"}
JSON.stringify([...m]);//'[[{"color":"black"},"22"],[0,"test"],[1,"a"]]'
let m = new Map([[2,"22"]]).set(0,'test').set(1,'a');
m //Map(3) {2 => "22", 0 => "test", 1 => "a"}
let obj = {};
for(let [k,v] of m){
obj[k] = v;
}
obj //{0: "test", 1: "a", 2: "22"}
JSON.stringify(obj);//'{"0":"test","1":"a","2":"22"}'
b.可以通过json-->Array-->map或json-->Object-->map的两种方式实现map转换成json
let j1 = '[[{"color":"black"},"22"],[0,"test"],[1,"a"]]';
let m = new Map(JSON.parse(j1));
m //Map(3) {{"color":"black"} => "22", 0 => "test", 1 => "a"}
let j1 = '{"0":"test","1":"a","2":"22"}';
let obj = JSON.parse(j1);
let m = new Map(Object.entries(obj));
m //Map(3) {"0" => "test", "1" => "a", "2" => "22"}
4.WeakMap
含义:用于生成键值对的集合,但是键名只能是对象或者null,而且WeakMap键名所引用的对象是弱引用。
语法:可以通过set来向WeakMap添加结构,也可以使用向WeakMap构造器中传参数的方式生成WeakMap结构
set/get/has/delete
let w1 = new WeakMap();
w1.set({name : "test"},"12");
w1.has({name : "test"});//false {name : "test"} === {name : "test"} 内存地址不同,WeakMap视为不同的值
let obj = {name : "test1"};
w1.set(obj,"0");
w1.has(obj);//true
w1.set(window,'window');
w1.has(window);//true
w1.delete(window);//true
let a1 = [1,2,3],a2 = [4,5,6];
let w2 = new WeakMap([[a1,'abc'],[a2,'def']]);
w2 //WeakMap {Array(3) => "def", Array(3) => "abc"}
w2.has(a2);//true
特点:同WeakSet,WeakMap键名指向的对象,不计入垃圾回收机制。
因此,只要WeakMap键名所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。
ES6学习笔记(10)----Set和Map数据结构的更多相关文章
- ES6学习总结之Set和Map数据结构的理解
前言 当我们需要存储一些数据的时候,首先想到的是定义一个变量用来存储,之后我们可能学了数组,发现数组比变量可以存储更多的数据,接着可能有其它的存储数据的方法等等,然而我今天需要介绍的是在ES6中比较常 ...
- ES6 学习笔记(十)Map的基本用法
1 基本用法 Map类型是键值对的有序列表,而键和值都可以是任意类型.可以看做Python中的字典(Dictionary)类型. 1.1 创建方法 Map本身是一个构造函数,用来生成Map实例,如: ...
- JS&ES6学习笔记(持续更新)
ES6学习笔记(2019.7.29) 目录 ES6学习笔记(2019.7.29) let和const let let 基本用法 let 不存在变量提升 暂时性死区 不允许重复声明 块级作用域 级作用域 ...
- ES6学习笔记之变量的解构赋值
变量的解构赋值 ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构. 数组的解构赋值 以前,为变量赋值,只能直接指定值: 1 2 3 var a = 1; var b = 2; ...
- 《C++ Primer Plus》学习笔记10
<C++ Primer Plus>学习笔记10 <<<<<<<<<<<<<<<<<&l ...
- es6学习笔记-class之一概念
前段时间复习了面向对象这一部分,其中提到在es6之前,Javasript是没有类的概念的,只从es6之后出现了类的概念和继承.于是乎,花时间学习一下class. 简介 JavaScript 语言中,生 ...
- golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息
golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...
- ES6学习笔记<四> default、rest、Multi-line Strings
default 参数默认值 在实际开发 有时需要给一些参数默认值. 在ES6之前一般都这么处理参数默认值 function add(val_1,val_2){ val_1 = val_1 || 10; ...
- ES6学习笔记<三> 生成器函数与yield
为什么要把这个内容拿出来单独做一篇学习笔记? 生成器函数比较重要,相对不是很容易理解,单独做一篇笔记详细聊一聊生成器函数. 标题为什么是生成器函数与yield? 生成器函数类似其他服务器端语音中的接口 ...
随机推荐
- Android自定义控件实现带有清除按钮的EditText
首先声明我也是参考了别人的思路,只是稍微做了下修改,增加显示密码与隐藏密码,没有输入字符串时让EditText进行抖动,废话少说这里附上效果图 效果很赞有木有 那么怎么实现这种效果呢?那就跟着我一起来 ...
- oracle实例的内存(SGA和PGA)调整,优化数据库性能
一.名词解释 (1)SGA:SystemGlobal Area是OracleInstance的基本组成部分,在实例启动时分配;系统全局域SGA主要由三部分构成:共享池.数据缓冲区.日志缓冲区. (2) ...
- HBase之七:事务和并发控制机制原理
作为一款优秀的非内存数据库,HBase和传统数据库一样提供了事务的概念,只是HBase的事务是行级事务,可以保证行级数据的原子性.一致性.隔离性以及持久性,即通常所说的ACID特性.为了实现事务特性, ...
- qq截图原理
屏幕截图实现的大体思想是:发起截图时,将当前窗口的图像保存到内存中,然后弹出一个置顶的全屏窗口,将保存的桌面图片绘制到这个全屏窗口上:初始时绘制的是灰化的桌面图像,选择截图区域后,则将选中的区域绘制成 ...
- View Controller Programming Guide for iOS---(三)---Using View Controllers in Your App
Using View Controllers in Your App Whether you are working with view controllers provided by iOS, or ...
- k8s-高级调度方式-二十一
两类: 节点选择器:nodeSelector(给node打上标签,pod通过标签预选节点),nodeName 节点亲和调度:nodeAffinity 1.节点选择器(nodeSelector,node ...
- Jquery之each函数详解
最近项目被each函数坑惨了,想来还是好好整理下关于each函数的方方面面,一来方便自己查阅,二来为读者提供经验和教训,废话不多说,来看看Each函数到底是怎么坑人的. 一. 全局jQuery.eac ...
- 几题LCS后的小总结
先得理解最长上升子序列吧,这还是非常简单的. 然后就是要真正理解LCS: 真正理解源于做题,做题就像查漏补缺一样,你总有不会的地方. 非常彻底地理解该图(还是去做题啦) = =瞎几把乱说有两种问题 [ ...
- P2579 [ZJOI2005]沼泽鳄鱼
传送门 话说邻接矩阵居然还能快速幂的么-- 把原图的邻接矩阵\(G\)打出来,那么\(G[u][v]\)表示一秒后\(u\)到\(v\)的方案数,\(G^2[u][v]\)表示\(2\)秒后的方案数- ...
- luogu P1095守望者的逃离【dp】By cellur925
题目传送门 考虑dp,设f[i]表示到第i时间,能到达的最远距离.因为题目涉及了三种操作:1,补血消耗魔法值:2, 等待增加魔法值:3,直接向前走.而1,3和2,3的操作是可以同时进行没有冲突的,所以 ...