参考书《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键名所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。
更多专业前端知识,请上 【猿2048】www.mk2048.com