參考書《ECMAScript 6入門》http://es6.ruanyifeng.com/Set和Map數據結構1.Set 基本用法 Set是一種新的數據結構,它的成員都是唯一的不重覆的。 let s1 = new Set(); s1.add({"name":"123"}); s1 // Set(1 ...
參考書《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鍵名所引用的對象的其他引用都被清除,垃圾回收機制就會釋放該對象所占用的記憶體。