深入理解ES6--7.Set和Map

你聽___發表於2018-04-30

深入理解ES6--7.Set和Map

主要知識點:Set的基本操作,Weak Set,Map的基本操作,Weak Map

Set和Map知識點

1.ES6中的Set

ES6中提供了Set資料容器,這是一個能夠儲存無重複值的有序列表。

建立Set

通過new Set()可以建立Set,然後通過add方法能夠向Set中新增資料項:

//Set
let set= new Set();
set.add(1);
set.add('1');
console.log(set.size);//2		
複製程式碼

Set內部使用Object.is()方法來判斷兩個資料項是否相等,唯一不同的是+0和-0在Set中被判斷為是相等的。

同時可以使用陣列來構造Set,或者說具有迭代器的物件都可以用來構造Set,並且Set構造器會確保不會存在重複的資料項:

let set = new Set([1,2,3,3,3,3]);
console.log(set.size);//3
複製程式碼

檢查某個值是否存在於Set中

可以使用has()方法來判斷某個值是否存在於Set中:

let set = new Set([1,2,3,3,3,3]);
console.log(set.has(5)); //false
複製程式碼

刪除值

使用delete()方法從Set中刪除某個值,或者使用clear()方法從Set中刪除所有值:

let set = new Set([1,2,3,3,3,3]);
console.log(set.size);//3
console.log(set.has(5)); //false

set.delete(1);

console.log(set.has(1)); //false
console.log(set.size); //2
複製程式碼

forEach()方法

可以使用forEach方法來遍歷Set中的資料項,該方法傳入一個回撥函式callback,還可以傳入一個this,用於回撥函式之中:

回撥函式callback中有三個引數:

  1. 元素值;

  2. 元素索引;

  3. 將要遍歷的物件;

     let set = new Set([1,2,3,3,3,3]);
     set.forEach(function (value,key,ownerSet) {
     	console.log(value);
     	console.log(key);			
     })
    複製程式碼

Set中的value和key是相同的,這是為了讓Set的forEach方法和陣列以及Map的forEach方法保持一致,都具有三個引數。

在forEach方法中傳入this,給回撥函式使用:

let set = new Set([1,2,3,3,3,3]);
let operation ={

	print(value){
		console.log(value);
	},

	iterate(set=[]){
		set.forEach(function(value,key,ownerSet){
			this.print(value);
			this.print(key);
		},this);
	}

}

operation.iterate(set);

輸出:1 1 2 2 3 3
複製程式碼

如果回撥函式使用箭頭函式的話,就可以省略this的入參,這是因為箭頭函式會通過作用域鏈找到當前this物件,將上面的示例程式碼使用箭頭函式來寫:

let set = new Set([1,2,3,3,3,3]);
let operation ={

	print(value){
		console.log(value);
	},

	iterate(set=[]){
		set.forEach((value,key)=>{
			this.print(value);
			this.print(key);
		})
	}

}

operation.iterate(set);
複製程式碼

將Set轉換成陣列

將陣列轉換成Set十分容易,可以將陣列傳入Set構造器即可;而將Set轉換成陣列,需要使用擴充套件運算子。擴充套件運算子能將陣列中的資料項切分開,作為獨立項傳入到函式,如果將擴充套件運算子用於可迭代物件的話,就可以將可迭代物件轉換成陣列:

let [...arr]=set;
console.log(arr); // [1,2,3]
複製程式碼

Weak Set

Set在存放物件時,實際上是存放的是物件的引用,即Set也被稱之為Strong Set。如果所儲存的物件被置為null,但是Set例項仍然存在的話,物件依然無法被垃圾回收器回收,從而無法釋放記憶體:

let set = new Set();
let key={};
let key2 = {};
set.add(key);
set.add(key2);
console.log(set.size); //2

key=null;
console.log(set.size); //2
複製程式碼

可以看出就算物件key置為null,但是由於是強引用的方式,Set例項還存在,物件key依然不會被回收。

如果想讓物件key正常釋放的話,可以使用Weak Set,此時,存放的是物件的弱引用,當物件只被Set弱引用的話,並不會阻止物件例項被回收。Weka Set同Set的用法幾乎一致。可以使用add()方法增加資料項,使用has()方法檢查Weak Set中是否包含某項,以及使用delete()方法刪除某一項。

let set = new WeakSet();
let key = {};	
set.add(key);
console.log(set.has(key)); //true
set.delete(key);
console.log(set.has(key)); //false
複製程式碼

但需要注意的是:Weak Set構造器不接受基本型別資料,只接受物件。同樣的可以使用可迭代的物件如陣列,來作為構造器引數,來建立Weak Set。

Weak Set和Set之間的差異

對於Weak Set和Set之間的重要差異:

  1. 對於Weak Set例項,若呼叫了add()方法時傳入了非物件的引數,則會丟擲錯誤。如果在has()或者delete()方法中傳入了非物件的引數則會返回false;
  2. Weak Set不可迭代,因此不能用於for-of迴圈;
  3. Weak Set 無法暴露出任何迭代器(例如 keys() 與 values() 方法) ,因此沒有任何程式設計手段可用於判斷 Weak Set 的內容;
  4. Weak Set沒有forEach()方法;
  5. Weak Set沒有size屬性;

3. ES6中的Map

ES6中提供了Map資料結構,能夠存放鍵值對,其中,鍵的去重是通過Object.is()方法進行比較,鍵的資料型別可以是基本型別資料也可以是物件,而值也可以是任意型別資料。

對Map的操作

  1. 使用set()方法可以給Map新增鍵值對

     let map = new Map();
     map.set('title','hello world');
     map.set('year','2018');
     
     console.log(map.size); //2
    複製程式碼

通過set()方法往Map中增加了兩個鍵值對後,可以看到Map的大小就為2;

  1. 通過get()方法可以從Map中提取值

     let map = new Map();
     map.set('title','hello world');
     map.set('year','2018');
     
     console.log(map.get('title')); // hello world
    複製程式碼
  2. has(),delete()以及clear()方法

為了和Set的操作保持一致,Map中同樣有has()方法,用來檢查某個資料項是否存在於Map中,使用delete方法可以從Map中刪除一個資料項,使用clear方法可以刪除Map中所有的資料項

let map = new Map();
map.set('title','hello world');
map.set('year','2018');

console.log(map.has('year')); //true
map.delete('title');
console.log(map.has('title')); //false
map.clear();
console.log(map.size); //0
複製程式碼

Map的初始化

與Set的初始化一樣,Map也可以用陣列來初始化Map,該陣列中的每一個資料項也是陣列,陣列的第一個資料項代表鍵值對的鍵,第二個資料項是鍵值對的值:

//使用陣列來建立Map
let map = new Map([['title','hello world'],['year','2018']]);
console.log(map.has('title')); //true
console.log(map.has('year')); //true
console.log(map.size); //2
複製程式碼

Map的forEach方法

與Set一樣,Map也擁有forEach方法,該方法也接收一個回撥函式,該回撥函式有三個引數:

  1. 鍵值對的鍵;

  2. 鍵值對的值;

  3. 當前Map物件引用;

     let map = new Map([['title','hello world'],['year','2018']]);
     map.forEach((value,key,ownerMap)=>{
     	console.log(value);
     	console.log(key);
     });
     
     hello world
     title
     2018
     year
    複製程式碼

與Set的forEach一樣,可以在回撥函式中傳入this引用

Weak Map

Weak Map對Map而言,就像是Weak Set相對於Set一樣:Weak Map(或者Weak Set)都是儲存物件弱引用的方式,在Weak Map(或者Weak Set)中,所有的鍵都必須是物件(嘗試使用非物件的鍵會丟擲錯誤),而且這些物件都是弱引用,不會干擾到垃圾回收。當Weak Map中的鍵在Weak Map之外不存在引用時,該鍵值對會被移除。

Weak Map的操作

  1. Weak Map的初始化

Weak Map的鍵必須是物件,值可以是任意型別,初始化同Map一樣,也可是使用陣列來建立一個 Weak Map :

//使用陣列來建立一個Weak Map
let key = {};
let key2 = {};
let map = new WeakMap([[key,'hello'],[key2,'world']]);
console.log(map.get(key)); //hello
console.log(map.get(key2)); //world
複製程式碼
  1. has方法以及delete方法

與Map一樣,可以使用has()方法來檢查Weak Map中是否存在某一個鍵值對,使用delete()方法可以刪除一個鍵值對。clear() 方法不存在,這是因為沒必要對鍵進行列舉,並且列舉 Weak Map 也是不可能的,這與 Weak Set 相同:

let key = {};
let key2 = {};
let map = new WeakMap([[key,'hello'],[key2,'world']]);

map.delete(key);
console.log(map.has(key)); //false
複製程式碼

Weak Map 的用法與侷限性 當決定是要使用 Weak Map 還是使用正規 Map 時,首要考慮因素在於你是否只想使用物件型別的鍵。如果你打算這麼做,那麼最好的選擇就是 Weak Map 。因為它能確保額外資料在不再可用後被銷燬,從而能優化記憶體使用並規避記憶體洩漏。

要記住 Weak Map 只為它們的內容提供了很小的可見度,因此你不能使用 forEach() 方法、size 屬性或 clear() 方法來管理其中的項。如果你確實需要一些檢測功能,那麼正規 Map會是更好的選擇,只是一定要確保留意記憶體的使用。

4. 總結

  1. Set 是無重複值的有序列表。根據 Object.is()方法來判斷其中的值不相等,以保證無重複。 Set 會自動移除重複的值,因此你可以使用它來過濾陣列中的重複值並返回結果。 Set並不是陣列的子型別,所以你無法隨機訪問其中的值。但你可以使用has() 方法來判斷某個值是否存在於 Set 中,或通過 size 屬性來檢視其中有多少個值。 Set 型別還擁有forEach()方法,用於處理每個值。

  2. Weak Set 是隻能包含物件的特殊 Set 。其中的物件使用弱引用來儲存,意味著當 Weak Set中的項是某個物件的僅存引用時,它不會遮蔽垃圾回收。由於記憶體管理的複雜性, Weak Set的內容不能被檢查,因此最好將 Weak Set 僅用於追蹤需要被歸組在一起的物件。

  3. Map 是有序的鍵值對,其中的鍵允許是任何型別。與 Set 相似,通過呼叫 Object.is()方法來判斷重複的鍵,這意味著能將數值 5 與字串 "5" 作為兩個相對獨立的鍵。使用set() 方法能將任何型別的值關聯到某個鍵上,並且該值此後能用 get() 方法提取出來。Map 也擁有一個 size 屬性與一個 forEach() 方法,讓專案訪問更容易。

  4. Weak Map 是隻能包含物件型別的鍵的特殊 Map 。與 Weak Set 相似,鍵的物件引用是弱引用,因此當它是某個物件的僅存引用時,也不會遮蔽垃圾回收。當鍵被回收之後,所關聯的值也同時從 Weak Map 中被移除。

相關文章