原創文章&經驗總結&從校招到A廠一路陽光一路滄桑
詳情請戳www.coderccc.com
> 主要知識點:Set的基本操作,Weak Set,Map的基本操作,Weak 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中有三個參數:
-
元素值;
-
元素索引;
-
將要遍歷的對象;
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之間的重要差異:
- 對於Weak Set實例,若調用了add()方法時傳入了非對象的參數,則會拋出錯誤。如果在has()或者delete()方法中傳入了非對象的參數則會返回false;
- Weak Set不可迭代,因此不能用於for-of循環;
- Weak Set 無法暴露出任何迭代器(例如 keys() 與 values() 方法) ,因此沒有任何編程手段可用於判斷 Weak Set 的內容;
- Weak Set沒有forEach()方法;
- Weak Set沒有size屬性;
3. ES6中的Map
ES6中提供了Map數據結構,能夠存放鍵值對,其中,鍵的去重是通過Object.is()方法進行比較,鍵的數據類型可以是基本類型數據也可以是對象,而值也可以是任意類型數據。
對Map的操作
-
使用
set()
方法可以給Map添加鍵值對let map = new Map();
map.set(‘title’,‘hello world’);
map.set(‘year’,‘2018’);console.log(map.size); //2
通過set()
方法往Map中增加了兩個鍵值對後,可以看到Map的大小就爲2;
-
通過get()方法可以從Map中提取值
let map = new Map();
map.set(‘title’,‘hello world’);
map.set(‘year’,‘2018’);console.log(map.get(‘title’)); // hello world
-
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
方法,該方法也接收一個回調函數,該回調函數有三個參數:
-
鍵值對的鍵;
-
鍵值對的值;
-
當前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的操作
- 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
- 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. 總結
-
Set 是無重複值的有序列表。根據
Object.is()
方法來判斷其中的值不相等,以保證無重複。 Set 會自動移除重複的值,因此你可以使用它來過濾數組中的重複值並返回結果。 Set並不是數組的子類型,所以你無法隨機訪問其中的值。但你可以使用has()
方法來判斷某個值是否存在於 Set 中,或通過size
屬性來查看其中有多少個值。 Set 類型還擁有forEach()
方法,用於處理每個值。 -
Weak Set 是隻能包含對象的特殊 Set 。其中的對象使用弱引用來存儲,意味着當 Weak Set中的項是某個對象的僅存引用時,它不會屏蔽垃圾回收。由於內存管理的複雜性, Weak Set的內容不能被檢查,因此最好將 Weak Set 僅用於追蹤需要被歸組在一起的對象。
-
Map 是有序的鍵值對,其中的鍵允許是任何類型。與 Set 相似,通過調用
Object.is()
方法來判斷重複的鍵,這意味着能將數值 5 與字符串 “5” 作爲兩個相對獨立的鍵。使用set()
方法能將任何類型的值關聯到某個鍵上,並且該值此後能用get()
方法提取出來。Map 也擁有一個size
屬性與一個forEach()
方法,讓項目訪問更容易。 -
Weak Map 是隻能包含對象類型的鍵的特殊 Map 。與 Weak Set 相似,鍵的對象引用是弱引用,因此當它是某個對象的僅存引用時,也不會屏蔽垃圾回收。當鍵被回收之後,所關聯的值也同時從 Weak Map 中被移除。