ES6之Set和Map資料結構

wade3po發表於2019-04-30

ES6提供了新的資料結構Set,類似陣列,元素值都是唯一的,不能重複。Set本身就是一個建構函式。

Set接受陣列或者類陣列作為引數用來初始化:

var arr1 = new Set([1, 2, 5, 1, 2]);

var arr2 = new Set('12512');

console.log(arr1);

console.log(arr2);
複製程式碼

ES6之Set和Map資料結構
會把重複的都去除,但是不會發生型別轉換,Set內部判斷兩個值類似===運算子,主要的區別就是NaN等於自身,三等的NaN會不等於自身。

var arr = new Set([NaN, NaN]);

console.log(arr);//NaN

console.log(NaN === NaN);//false
複製程式碼

Set的屬性和方法:

Add(value),新增某個值,返回Set結構本身:

var arr = new Set();

arr.add(1);

arr.add(2);

console.log(...arr);//1 2

複製程式碼

Delete(value),刪除某個值,返回布林值,表示成功失敗:

console.log(arr.delete(1));//true

has(value),返回一個布林值,表示該值是否為Set的成員。

console.log(arr.has(2));//true

Clear(),清除所有元素,無返回值:

arr.clear();

console.log(arr);//{}

Size,返回元素總數:

console.log(arr.size);//2

Array.form可以把Set資料結構轉成陣列,可以用來去重:

var arr = [1, 2, 1, 3, 4, 3, 2, 1, 5, 2];

var setArr = new Set(arr);

console.log(Array.from(setArr));//[1, 2, 3, 4, 5]
複製程式碼

遍歷keys、values、entries:

Set資料結構沒有鍵名,也可以說鍵名鍵值是同一個,所以這三個遍歷出來的都一樣,區分的話就是keys是鍵名,values是鍵值,entries是鍵值對:

var arr = new Set(['a', 'b', 'c']);

for(var i of arr.keys()){  

  console.log(i);//a b c

}

for(var i of arr.values()){  

  console.log(i);//a b c

}

for(var i of arr.entries()){  

  console.log(i);//['a', 'a'] ["b", "b"] ["c", "c"]

}
複製程式碼

Set結構預設可遍歷,預設遍歷的就是values,可以用for of直接遍歷:

for(var i of arr){  

  console.log(i);//a b c

}
複製程式碼

Set結構也可以用forEach遍歷,因為Set結構可以用擴充套件運算子,可以變通的陣列去重和使用陣列的遍歷方法:

var arr = [1, 2, 1, 3, 4, 3, 2, 1, 5, 2];

console.log([...new Set(arr)]);//[1, 2, 3, 4, 5]
複製程式碼

ES6提供了跟Set結構類似的WeakSet,也是不重複的集合,但是WeakSet只能是物件,其他型別的值都會報錯:

var ws = new WeakSet();

ws.add(1)//TypeError

ws.add('a')//TypeError

ws.add({a: 10})
複製程式碼

垃圾回收機制不會回收被全域性引用的變數,而WeakSet 中的物件都是弱引用,即垃圾回收機制不考慮 WeakSet 對該物件的引用。

如果其他物件都不再引用該物件,那麼垃圾回收機制會自動回收該物件所佔用的記憶體,不考慮該物件還存在於 WeakSet 之中。

WeakSet 裡面的引用,都不計入垃圾回收機制,因此,WeakSet 適合臨時存放一組物件,以及存放跟物件繫結的資訊。只要這些物件在外部消失,它在 WeakSet 裡面的引用就會自動消失。

由於上面這個特點,WeakSet 的成員是不適合引用的,因為它會隨時消失。另外,由於 WeakSet 內部有多少個成員,取決於垃圾回收機制有沒有執行,執行前後很可能成員個數是不一樣的,而垃圾回收機制何時執行是不可預測的,因此 ES6 規定 WeakSet 不可遍歷。

總結一下就是,WeakSet的例項物件就算是全域性的,也有可以被直接回收。

WeskSet有add、delete、has方法沒跟Set一樣,但是隻能是物件或者類似物件的陣列,比如:

var ws = new WeakSet();

ws.add([[1, 1], [2, 2]])

WeakSet沒有size屬性,不能遍歷。因此WeakSet的一個作用就是用來儲存DOM節點。其他還真不知道什麼用。

ES6提供了Map資料結構本質上還是鍵值對的集合,但是傳統物件只能是字串做鍵名,比如:

var el = document.getElementById('te');

var obj = {};

obj[el] = 'te';

console.log(obj);//{[object HTMLDivElement]: "te"}
複製程式碼

Map資料結構最主要的就是解決這個問題,鍵值還可以是物件:

var el = document.getElementById('te');

var obj = new Map();

obj.set(el, 'te');

console.log(obj);//{{div#te => "te"}
複製程式碼

Map有set、get、delete、clear和has方法和size屬性:

console.log(obj.get(el));//'te'

console.log(obj.has(el));//true

console.log(obj.size);//1

obj.delete(el);

obj.clear();

console.log(obj.has(el));//false
複製程式碼

Map接收的陣列引數的時候,一定是這樣的:

var obj = new Map([['a', 'a'], ['b', 'b']]);

其他的操作就跟普通物件操作原理一樣,只有一個需要注意,Map的鍵跟記憶體地址有關:

var map = new Map();

map.set(['a'], 123);

console.log(map.get(['a']));//undefined
複製程式碼

陣列的記憶體地址是不同的

map.set(-0, 123);

console.log(map.get(+0)); // 123

map.set(true, 1);

map.set('true', 2);

console.log(map.get(true)); // 1

console.log(map.get('true')); // 2

map.set(undefined, 3);

map.set(null, 4);

console.log(map.get(undefined)); // 3

map.set(NaN, 123);

console.log(map.get(NaN)); // 123
複製程式碼

Map和Set一樣,也有keys、values、entries和forEach遍歷方法,且順序就是插入順序,使用for of方法,同樣的,使用擴充套件運算子也能很快的轉為陣列,轉成陣列之後也就間接的能使用陣列的map、filter等陣列方法。這邊就不上程式碼了,跟Set一樣。

Map資料結構,可以直接或者間接的準成陣列或者JSON或者物件,相應的,陣列或者JSON或者物件也能轉成Map資料結構。

ES6提供了跟Map類似的WeakMap資料結構,兩者都差不多,區別有兩點,第一就是WeakMap的鍵一定要物件,否則報錯,另外一點跟WeakSet一樣,不計入垃圾回收機制。

它的鍵名所引用的物件都是弱引用,即垃圾回收機制不將該引用考慮在內。因此,只要所引用的物件的其他引用都被清除,垃圾回收機制就會釋放該物件所佔用的記憶體。也就是說,一旦不再需要,WeakMap 裡面的鍵名物件和所對應的鍵值對會自動消失,不用手動刪除引用。

要注意的是,是鍵名是弱引用,鍵值依然可以使用:

var map = new WeakMap();

var key = {};

var val = 'map';

map.set(key, val);

val = null;

console.log(map.get(key));//map
複製程式碼

也就是說val即使是消除了,WeakMap內部依然能使用。

因為WeakMap和Map的區別,鍵名是否存在不可預測,跟垃圾回收機制是否執行有關,所以WeakMap其他方法都沒有隻有get、set、has、delete方法。

WeakMap典型場合也是DOM節點作為鍵名,一旦DOM節點刪除了,WeakMap裡面的也會隨之消失,不會造成記憶體洩漏風險:

var map = new WeakMap();

var key = document.getElementById('te');

var val = 1;

map.set(key, val);

key.addEventListener('click', function() {  

  let val = myWeakmap.get(myElement);  

  val++;

}, false);
複製程式碼

一旦DOM節點消失,那麼該val也會消失。

Coding 個人筆記

ES6之Set和Map資料結構

相關文章