摘要:返回一個(gè)布爾值,表示該值是否為的成員。清除所有成員,沒有返回值。該數(shù)組中的每一項(xiàng)也必須是數(shù)組,內(nèi)部數(shù)組的首個(gè)項(xiàng)會(huì)作為鍵,第二項(xiàng)則為對(duì)應(yīng)值。返回所有成員的遍歷器需要特別注意的是,的遍歷順序就是插入順序。
Js大部分歷史時(shí)期都只存在一種集合類型,也就是數(shù)組類型。數(shù)組在 JS 中的使用正如其他語言的數(shù)組一樣,但缺少更多類型的集合導(dǎo)致數(shù)組也經(jīng)常被當(dāng)作隊(duì)列與棧來使用。數(shù)組只使用了數(shù)值型的索引,而如果非數(shù)值型的索引是必要的,開發(fā)者便會(huì)使用非數(shù)組的對(duì)象。這種技巧引出了非數(shù)組對(duì)象的定制實(shí)現(xiàn),即 Set 與 Map 。
Set: Set概述? Set結(jié)構(gòu)類似于數(shù)組,但是沒有重復(fù)結(jié)構(gòu)
? Set會(huì)自動(dòng)移除重復(fù)的值,因此可以用來過濾數(shù)組中的重復(fù)結(jié)構(gòu)
? Set內(nèi)的對(duì)象是強(qiáng)引用
a) let set = new Set([1, 2, 3, 4]);
Set 構(gòu)造器實(shí)際上可以接收任意可迭代對(duì)象作為參數(shù)。能使用數(shù)組是因?yàn)樗鼈兡J(rèn)就是可迭代的,Set與Map也是一樣,Set構(gòu)造器會(huì)使用迭代器來提取參數(shù)中的值
b) let set = new Set();
set.add(1);
set.add(2);
set.add(2);
//如果add對(duì)相同的值進(jìn)行了多次調(diào)用,那么那么在第一次之后的調(diào)用實(shí)際上會(huì)被忽略
set.add(3);
set.add("3");
// Set 不會(huì)使用強(qiáng)制類型轉(zhuǎn)換來判斷值是否重復(fù)。這意味著 Set 可以同時(shí)包含數(shù)值 3 與 字符串 "3" ,將它們都作為相對(duì)獨(dú)立的項(xiàng).
Set判斷是否重復(fù)使用了Object.is() 方法,唯一的例外是 +0 與 -0 在 Set 中被判斷為是相等的
c) 還可以向Set添加多個(gè)值相同的對(duì)象,他們不會(huì)被合并為同一項(xiàng)。
let set = new Set();
let key1 = {};
let key2 = {};
set.add(key1);
set.add(key2);
Set.prototype.constructor:構(gòu)造函數(shù),默認(rèn)就是Set函數(shù)。
Set.prototype.size:返回Set實(shí)例的成員總數(shù)。
Set的方法分為兩類:操作方法 和 遍歷方法
2.1、操作方法:? add(value):添加某個(gè)值,返回 Set 結(jié)構(gòu)本身。
因?yàn)榉祷豷et本身,所以可以寫成:
set.add(1).add(2).add(3)
? delete(value):刪除某個(gè)值,返回一個(gè)布爾值,表示刪除是否成功。
set.delete(2) ; // true
? has(value):返回一個(gè)布爾值,表示該值是否為Set的成員。
set.has(2) ; // false
? clear():清除所有成員,沒有返回值。
forEach():使用回調(diào)函數(shù)遍歷每個(gè)成員
es5給數(shù)組添加了forEach()方法,使得更容易處理數(shù)組中的每一項(xiàng),沒有返回值
對(duì)于數(shù)組來說forEach的三個(gè)參數(shù):
arr[].forEach(function(value,index,array){//do})
value數(shù)組中的當(dāng)前項(xiàng), index當(dāng)前項(xiàng)的索引, array原始數(shù)組
但是對(duì)于Set來說:
let set2 = new Set([{"a":1}, {"b":2}]);
set2.forEach(function(value, key, ownerSet) {
console.log(ownerSet === set2);
console.log(value === key);
});
key 與 value 總是相同的,同時(shí) ownerSet 也始終等于 set 。此代碼輸出:
true
true
true
true
如果想在回調(diào)函數(shù)中使用當(dāng)前的this,還可以在forEach中傳入this作為第二個(gè)參數(shù)
let set = new Set([1, 2]);
let processor = {
output(value) { console.log(value);
},
process(dataSet) {
dataSet.forEach(function(value) { this.output(value); }, this);
}
};
processor.process(set);
本例中,在processor.process方法中的set調(diào)用了forEach方法,并傳遞了this作為第二個(gè)參數(shù),這樣便能正確的調(diào)用到this.output()方法
或者也可以使用箭頭函數(shù)來達(dá)到相同的效果,無需傳入this,只需將上邊的process改寫成:
process(dataSet) {
dataSet.forEach((value) => this.output(value));
}
keys()、values()和entries()
keys():返回鍵名的遍歷器
values():返回鍵值的遍歷器
entries():返回鍵值對(duì)的遍歷器
keys方法、values方法、entries方法返回的都是遍歷器對(duì)象,由于Set結(jié)構(gòu)沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個(gè)值),所以keys方法和values方法的行為完全一致。
let set = new Set(["red", "green", "blue"]);
for (let item of set.keys()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.entries()) {
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
上面代碼中,entries方法返回的遍歷器,同時(shí)包括鍵名和鍵值,所以每次輸出一個(gè)數(shù)組,它的兩個(gè)成員完全相等。
Set 結(jié)構(gòu)的實(shí)例默認(rèn)可遍歷,它的默認(rèn)遍歷器生成函數(shù)就是它的values方法。
Set.prototype[Symbol.iterator] === Set.prototype.values
// true
這就意味著,可以省略values方法,直接用for…of循環(huán)遍歷Set
let set = new Set(["red", "green", "blue"]);
for (let x of set) {
console.log(x);
}
// red
// green
// blue
Set最經(jīng)典的應(yīng)用就是數(shù)組排重,
Set的內(nèi)部實(shí)現(xiàn)Set的對(duì)象通過指針指向的內(nèi)存中的地址來做比較,所以要判斷對(duì)象是否相等,只能通過遍歷去判斷,這其中包含了很多邊際情況。所以set沒有去判斷這些,只要往里面扔一個(gè)對(duì)象,那么就是一個(gè)新的元素
Set與其他數(shù)據(jù)結(jié)構(gòu)的互相轉(zhuǎn)換 1、 Set與數(shù)組的轉(zhuǎn)換 1.1、 Set轉(zhuǎn)數(shù)組使用擴(kuò)展運(yùn)算符可以很簡(jiǎn)單的將Set轉(zhuǎn)成數(shù)組
let set = new Set([1, 2, 3, 3, 3, 4, 5]),
let array = [...set];
console.log(array); // [1,2,3,4,5]
該示例很好的說明了Set的一個(gè)重要的功能,數(shù)組排重,當(dāng)然也很好的展示了,如何從Set轉(zhuǎn)成數(shù)組的過程。
注意,這種轉(zhuǎn)變是生成了一個(gè)新的數(shù)組對(duì)象原來的Set依然存在。
如最初的構(gòu)造示例:
let set = new Set([1,4,5,6,7]);
主要寫自身特性和與Set的區(qū)別?
驗(yàn)證:外部賦空看內(nèi)部是否變化?
外部回收后?
由于 Set 類型存儲(chǔ)對(duì)象引用的方式,它也可以被稱為 Strong Set 。對(duì)象存儲(chǔ)在 Set 的一個(gè)實(shí)例中時(shí),實(shí)際上相當(dāng)于把對(duì)象存儲(chǔ)在變量中。只要對(duì)于 Set 實(shí)例的引用仍然存在,所存儲(chǔ)的對(duì)象就無法被垃圾回收機(jī)制回收,從而無法釋放內(nèi)存。
當(dāng) JS 代碼在網(wǎng)頁中運(yùn)行,同時(shí)你想保持與 DOM 元素的聯(lián)系,在該元素可能被其他腳本移除的情況下,你應(yīng)當(dāng)不希望自己的代碼保留對(duì)該 DOM 元素的最后一個(gè)引用(這種情況被稱為內(nèi)存泄漏)
為了緩解這個(gè)問題, ES6 也包含了 Weak Set ,該類型只允許存儲(chǔ)對(duì)象弱引用,而不能存儲(chǔ)基本類型的值。對(duì)象的弱引用在它自己成為該對(duì)象的唯一引用時(shí),不會(huì)阻止垃圾回收
WeakSet 結(jié)構(gòu)有以下三個(gè)方法。
WeakSet.prototype.add(value):向 WeakSet 實(shí)例添加一個(gè)新成員。
WeakSet.prototype.delete(value):清除 WeakSet 實(shí)例的指定成員。
WeakSet.prototype.has(value):返回一個(gè)布爾值,表示某個(gè)值是否在 WeakSet 實(shí)例之中。
對(duì)于 WeakSet 的實(shí)例,若調(diào)用 add() 方法時(shí)傳入了非對(duì)象的參數(shù),就會(huì)拋出錯(cuò)誤(
has() 或 delete() 則會(huì)在傳入了非對(duì)象的參數(shù)時(shí)返回 false );
Weak Set 不可迭代,因此不能被用在 for-of 循環(huán)中;
Weak Set 無法暴露出任何迭代器(例如 keys() 與 values() 方法),因此沒有任何編
程手段可用于判斷 Weak Set 的內(nèi)容;
Weak Set 沒有 forEach() 方法;
Weak Set 沒有 size 屬性。
WeakSet之所以不可遍歷是由于 WeakSet 內(nèi)部有多少個(gè)成員,取決于垃圾回收機(jī)制有沒有運(yùn)行,運(yùn)行前后很可能成員個(gè)數(shù)是不一樣的,而垃圾回收機(jī)制何時(shí)運(yùn)行是不可預(yù)測(cè)的,因此 ES6 規(guī)定 WeakSet 不可遍歷。
WeakSet常用場(chǎng)景
Weak Set 看起來功能有限,而這對(duì)于正確管理內(nèi)存而言是必要的。一般來說,若只想追蹤對(duì)象的引用,應(yīng)當(dāng)使用 Weak Set 而不是正規(guī) Set
如果Set中引用了不再需要的大型對(duì)象,如已經(jīng)從DOM樹中刪除的DOM元素,那么其回收代價(jià)是昂貴的
JavaScript 的對(duì)象(Object),本質(zhì)上是鍵值對(duì)的集合(Hash 結(jié)構(gòu)),但是傳統(tǒng)上只能用字符串當(dāng)作鍵。這給它的使用帶來了很大的限制。
為了解決這個(gè)問題,ES6 提供了 Map 數(shù)據(jù)結(jié)構(gòu)。它類似于對(duì)象,也是鍵值對(duì)的集合,但是“鍵”的范圍不限于字符串,各種類型的值(包括對(duì)象)都可以當(dāng)作鍵。也就是說,Object 結(jié)構(gòu)提供了“字符串—值”的對(duì)應(yīng),Map 結(jié)構(gòu)提供了“值—值”的對(duì)應(yīng),是一種更完善的 Hash 結(jié)構(gòu)實(shí)現(xiàn)。如果你需要“鍵值對(duì)”的數(shù)據(jù)結(jié)構(gòu),Map 比 Object 更合適。
ES6 的 Map 類型是鍵值對(duì)的有序列表,而鍵和值都可以是任意類型。鍵的比較使用的是Object.is() ,因此你能將 5 與 "5" 同時(shí)作為鍵,因?yàn)樗鼈冾愋筒煌_@與使用對(duì)象屬性
作為鍵的方式(指的是用對(duì)象來模擬 Map )截然不同,因?yàn)閷?duì)象的屬性會(huì)被強(qiáng)制轉(zhuǎn)換為字符串。
你可以調(diào)用 set() 方法并給它傳遞一個(gè)鍵與一個(gè)關(guān)聯(lián)的值,來給 Map 添加項(xiàng);此后使用鍵名來調(diào)用 get() 方法便能提取對(duì)應(yīng)的值。例如:
let map = new Map();
map.set("title", "Understanding ES6");
map.set("year", 2016);
console.log(map.get("title")); // "Understanding ES6"
console.log(map.get("year")); // 2016
依然與 Set 類似,你能將數(shù)組傳遞給 Map 構(gòu)造器,以便使用數(shù)據(jù)來初始化一個(gè) Map 。該數(shù)組中的每一項(xiàng)也必須是數(shù)組,內(nèi)部數(shù)組的首個(gè)項(xiàng)會(huì)作為鍵,第二項(xiàng)則為對(duì)應(yīng)值。因此整個(gè)Map 就被這些雙項(xiàng)數(shù)組所填充。例如:
let map = new Map([["name", "Nicholas"], ["age", 25]]);
console.log(map.has("name")); // true
console.log(map.get("name")); // "Nicholas"
console.log(map.size); // 2
通過構(gòu)造器中的初始化, "name" 與 "age" 這兩個(gè)鍵就被添加到 map 變量中。雖然由數(shù)組構(gòu)成的數(shù)組看起來有點(diǎn)奇怪,這對(duì)于準(zhǔn)確表示鍵來說卻是必要的:因?yàn)殒I允許是任意數(shù)據(jù)類型,將鍵存儲(chǔ)在數(shù)組中,是確保它們?cè)诒惶砑拥?Map 之前不會(huì)被強(qiáng)制轉(zhuǎn)換為其他類型的唯一方法。
Map構(gòu)造函數(shù)接受數(shù)組作為參數(shù),實(shí)際上執(zhí)行的是下面的算法。
const items = [
["name", "Nicholas"]
["age", 25] ]
const map = new Map();
items.forEach(
([key, value]) => map.set(key, value)
);
事實(shí)上,不僅僅是數(shù)組,任何具有 Iterator 接口、且每個(gè)成員都是一個(gè)雙元素的數(shù)組的數(shù)據(jù)結(jié)構(gòu)都可以當(dāng)做Map構(gòu)造函數(shù)的參數(shù)。這就是說,Set和Map都可以用來生成新的Map
其他構(gòu)造const set = new Set([
["foo", 1],
["bar", 2]
]);
const m1 = new Map(set);
m1.get("foo") // 1
const m2 = new Map([["baz", 3]]);
const m3 = new Map(m2);
m3.get("baz") // 3
上面代碼中,我們分別使用 Set 對(duì)象和 Map 對(duì)象,當(dāng)作Map構(gòu)造函數(shù)的參數(shù),結(jié)果都生成了新的 Map 對(duì)象。
Map 同樣擁有 size 屬性,用于指明包含了多少個(gè)鍵值對(duì)。以下代碼用不同方式使用了這三種方法以及 size 屬性:
2方法 2.1、操作方法set方法設(shè)置鍵名key對(duì)應(yīng)的鍵值為value,然后返回整個(gè) Map 結(jié)構(gòu)。如果key已經(jīng)有值,則鍵值會(huì)被更新,否則就新生成該鍵。
const m = new Map();
m.set("edition", 6) // 鍵是字符串
m.set(262, "standard") // 鍵是數(shù)值
m.set(undefined, "nah") // 鍵是 undefined
set方法返回的是當(dāng)前的Map對(duì)象,因此可以采用鏈?zhǔn)綄懛ā?br>let map = new Map()
.set(1, "a")
.set(2, "b")
.set(3, "c");
get方法讀取key對(duì)應(yīng)的鍵值,如果找不到key,返回undefined。
const m = new Map();
const hello = function() {console.log("hello");};
m.set(hello, "Hello ES6!") // 鍵是函數(shù)
m.get(hello) // Hello ES6!
2.13、has、delete、clearMap 與 Set 共享了幾個(gè)方法,這是有意的,允許你使用相似的方式來與 Map 及 Set 進(jìn)行交互。以下三個(gè)方法在 Map 與 Set 上都存在:
has方法返回一個(gè)布爾值,表示某個(gè)鍵是否在當(dāng)前 Map 對(duì)象之中。
const m = new Map();
m.set("edition", 6);
m.set(262, "standard");
m.set(undefined, "nah");
m.has("edition") // true
m.has("years") // false
m.has(262) // true
m.has(undefined) // true
delete方法刪除某個(gè)鍵,返回true。如果刪除失敗,返回false。
const m = new Map();
m.set(undefined, "nah");
m.has(undefined) // true
m.delete(undefined)
m.has(undefined) // false
clear方法清除所有成員,沒有返回值。
let map = new Map();
map.set("foo", true);
map.set("bar", false);
map.size // 2
map.clear()
map.size // 0
? keys():返回鍵名的遍歷器。
? values():返回鍵值的遍歷器。
? entries():返回所有成員的遍歷器
需要特別注意的是,Map 的遍歷順序就是插入順序。
const map = new Map([
["F", "no"],
["T", "yes"],
]);
for (let key of map.keys()) {
console.log(key);
}
// "F"
// "T"
for (let value of map.values()) {
console.log(value);
}
// "no"
// "yes"
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"
// 等同于使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"
上面代碼最后的那個(gè)例子,表示 Map 結(jié)構(gòu)的默認(rèn)遍歷器接口(Symbol.iterator屬性),就是entries方法。
Map 的 forEach() 方法類似于 Set 與數(shù)組的同名方法,它接受一個(gè)能接收三個(gè)參數(shù)的回調(diào)函數(shù):
Map 中下個(gè)位置的值;
該值所對(duì)應(yīng)的鍵;
目標(biāo) Map 自身。
回調(diào)函數(shù)的這些參數(shù)更緊密契合了數(shù)組 forEach() 方法的行為,即:第一個(gè)參數(shù)是值、第二個(gè)參數(shù)則是鍵(數(shù)組中的鍵是數(shù)值索引)。此處有個(gè)示例:
let map = new Map([
["name", "Nicholas"],
["age", 25]
]);
map.forEach(function(value, key, ownerMap) {
console.log(key + " " + value);
console.log(ownerMap === map);
});
forEach() 的回調(diào)函數(shù)輸出了傳給它的信息。其中 value 與 key 被直接輸出, ownerMap
與 map 進(jìn)行了比較,說明它們是相等的。這就輸出了:
name Nicholas
true
age 25
true
Map 結(jié)構(gòu)轉(zhuǎn)為數(shù)組結(jié)構(gòu),比較快速的方法是使用擴(kuò)展運(yùn)算符(...)。
const map = new Map([
[1, "one"],
[2, "two"],
[3, "three"],
]);
[...map.keys()]
// [1, 2, 3]
[...map.values()]
// ["one", "two", "three"]
[...map.entries()]
// [[1,"one"], [2, "two"], [3, "three"]]
[...map]
// [[1,"one"], [2, "two"], [3, "three"]]
將數(shù)組傳入 Map 構(gòu)造函數(shù),就可以轉(zhuǎn)為 Map。
new Map([
[true, 7],
[{foo: 3}, ["abc"]]
])
// Map {
// true => 7,
// Object {foo: 3} => ["abc"]
// }
如果所有 Map 的鍵都是字符串,它可以無損地轉(zhuǎn)為對(duì)象。
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [k,v] of strMap) {
obj[k] = v;
}
return obj;
}
const myMap = new Map()
.set("yes", true)
.set("no", false);
strMapToObj(myMap)
// { yes: true, no: false }
如果有非字符串的鍵名,那么這個(gè)鍵名會(huì)被轉(zhuǎn)成字符串,再作為對(duì)象的鍵名。
function objToStrMap(obj) {
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k, obj[k]);
}
return strMap;
}
objToStrMap({yes: true, no: false})
// Map {"yes" => true, "no" => false}
Map 轉(zhuǎn)為 JSON 要區(qū)分兩種情況。一種情況是,Map 的鍵名都是字符串,這時(shí)可以選擇轉(zhuǎn)為對(duì)象 JSON。
function strMapToJson(strMap) {
return JSON.stringify(strMapToObj(strMap));
}
let myMap = new Map().set("yes", true).set("no", false);
strMapToJson(myMap)
// "{"yes":true,"no":false}"
另一種情況是,Map 的鍵名有非字符串,這時(shí)可以選擇轉(zhuǎn)為數(shù)組 JSON。
function mapToArrayJson(map) {
return JSON.stringify([...map]);
}
let myMap = new Map().set(true, 7).set({foo: 3}, ["abc"]);
mapToArrayJson(myMap)
// "[[true,7],[{"foo":3},["abc"]]]"
JSON 轉(zhuǎn)為 Map,正常情況下,所有鍵名都是字符串。
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap("{"yes": true, "no": false}")
// Map {"yes" => true, "no" => false}
但是,有一種特殊情況,整個(gè) JSON 就是一個(gè)數(shù)組,且每個(gè)數(shù)組成員本身,又是一個(gè)有兩個(gè)成員的數(shù)組。這時(shí),它可以一一對(duì)應(yīng)地轉(zhuǎn)為 Map。這往往是 Map 轉(zhuǎn)為數(shù)組 JSON 的逆操作。
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap("[[true,7],[{"foo":3},["abc"]]]")
// Map {true => 7, Object {foo: 3} => ["abc"]}
WeakMap與Map的區(qū)別有兩點(diǎn)。
首先,WeakMap只接受對(duì)象作為鍵名(null除外),不接受其他類型的值作為鍵名。
const map = new WeakMap();
map.set(1, 2)
// TypeError: 1 is not an object!
map.set(Symbol(), 2)
// TypeError: Invalid value used as weak map key
map.set(null, 2)
// TypeError: Invalid value used as weak map key
其次,WeakMap的鍵名所指向的對(duì)象,不計(jì)入垃圾回收機(jī)制。
WeakMap的設(shè)計(jì)目的在于,有時(shí)我們想在某個(gè)對(duì)象上面存放一些數(shù)據(jù),但是這會(huì)形成對(duì)于這個(gè)對(duì)象的引用。請(qǐng)看下面的例子。
const e1 = document.getElementById("foo");
const e2 = document.getElementById("bar");
const arr = [
[e1, "foo 元素"],
[e2, "bar 元素"],
];
上面代碼中,e1和e2是兩個(gè)對(duì)象,我們通過arr數(shù)組對(duì)這兩個(gè)對(duì)象添加一些文字說明。這就形成了arr對(duì)e1和e2的引用。
一旦不再需要這兩個(gè)對(duì)象,我們就必須手動(dòng)刪除這個(gè)引用,否則垃圾回收機(jī)制就不會(huì)釋放e1和e2占用的內(nèi)存。
// 不需要 e1 和 e2 的時(shí)候
// 必須手動(dòng)刪除引用
arr [0] = null;
arr [1] = null;
上面這樣的寫法顯然很不方便。一旦忘了寫,就會(huì)造成內(nèi)存泄露。
WeakMap 就是為了解決這個(gè)問題而誕生的,它的鍵名所引用的對(duì)象都是弱引用,即垃圾回收機(jī)制不將該引用考慮在內(nèi)。因此,只要所引用的對(duì)象的其他引用都被清除,垃圾回收機(jī)制就會(huì)釋放該對(duì)象所占用的內(nèi)存。也就是說,一旦不再需要,WeakMap 里面的鍵名對(duì)象和所對(duì)應(yīng)的鍵值對(duì)會(huì)自動(dòng)消失,不用手動(dòng)刪除引用。
ES6 的 WeakMap 類型是鍵值對(duì)的無序列表,其中鍵必須是非空的對(duì)象,值則允許是任意類型。 WeakMap 的接口與 Map 的非常相似
// WeakMap 可以使用 set 方法添加成員
const wm1 = new WeakMap();
const key = {foo: 1};
wm1.set(key, 2);
wm1.get(key) // 2
// WeakMap 也可以接受一個(gè)數(shù)組,
// 作為構(gòu)造函數(shù)的參數(shù)
const k1 = [1, 2, 3];
const k2 = [4, 5, 6];
const wm2 = new WeakMap([[k1, "foo"], [k2, "bar"]]);
wm2.get(k2) // "bar"
WeakMap的屬性和方法:
WeakMap 與 Map 在 API 上的區(qū)別主要是兩個(gè),一是沒有遍歷操作(即沒有keys()、values()和entries()方法),也沒有size屬性。因?yàn)闆]有辦法列出所有鍵名,某個(gè)鍵名是否存在完全不可預(yù)測(cè),跟垃圾回收機(jī)制是否運(yùn)行相關(guān)。這一刻可以取到鍵名,下一刻垃圾回收機(jī)制突然運(yùn)行了,這個(gè)鍵名就沒了,為了防止出現(xiàn)不確定性,就統(tǒng)一規(guī)定不能取到鍵名。二是無法清空,即不支持clear方法。因此,WeakMap只有四個(gè)方法可用:get()、set()、has()、delete()。
const wm = new WeakMap();
// size、forEach、clear 方法都不存在
wm.size // undefined
wm.forEach // undefined
wm.clear // undefined
Weak Map 的最佳用武之地,就是在瀏覽器中創(chuàng)建一個(gè)關(guān)聯(lián)到特定 DOM 元素的對(duì)象。例如,某些用在網(wǎng)頁上的 JS 庫(kù)會(huì)維護(hù)一個(gè)自定義對(duì)象,用于引用該庫(kù)所使用的每一個(gè) DOM 元素,并且其映射關(guān)系會(huì)存儲(chǔ)在內(nèi)部的對(duì)象緩存中。
該方法的困難之處在于:如何判斷一個(gè) DOM 元素已不復(fù)存在于網(wǎng)頁中,以便該庫(kù)能移除此元素的關(guān)聯(lián)對(duì)象。若做不到,該庫(kù)就會(huì)繼續(xù)保持對(duì) DOM 元素的一個(gè)無效引用,并造成內(nèi)存泄漏。使用 Weak Map 來追蹤 DOM 元素,依然允許將自定義對(duì)象關(guān)聯(lián)到每個(gè) DOM 元素,而在此對(duì)象所關(guān)聯(lián)的 DOM 元素不復(fù)存在時(shí),它就會(huì)在 Weak Map 中被自動(dòng)銷毀。
必須注意的是, Weak Map 的鍵才是弱引用,而值不是。在 Weak Map 的值中存儲(chǔ)對(duì)象會(huì)阻止垃圾回收,即使該對(duì)象的其他引用已全都被移除。
當(dāng)決定是要使用 Weak Map 還是使用正規(guī) Map 時(shí),首要考慮因素在于你是否只想使用對(duì)象類型的鍵。如果你打算這么做,那么最好的選擇就是 Weak Map 。因?yàn)樗艽_保額外數(shù)據(jù)在不再可用后被銷毀,從而能優(yōu)化內(nèi)存使用并規(guī)避內(nèi)存泄漏。
要記住 Weak Map 只為它們的內(nèi)容提供了很小的可見度,因此你不能使用 forEach() 方法、size 屬性或 clear() 方法來管理其中的項(xiàng)。如果你確實(shí)需要一些檢測(cè)功能,那么正規(guī) Map會(huì)是更好的選擇,只是一定要確保留意內(nèi)存的使用。
//map和set 比較的方法是不是一樣
NaN 和 +0 -0
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/96813.html
摘要:學(xué)習(xí)筆記工作中常用到的語法只是簡(jiǎn)單提及和,今天有空于是寫了這篇文章深入理解中的和數(shù)據(jù)結(jié)構(gòu),與其它數(shù)據(jù)結(jié)構(gòu)的互相轉(zhuǎn)換。的提供了新的數(shù)據(jù)結(jié)構(gòu)。本身是一個(gè)構(gòu)造函數(shù),用來生成數(shù)據(jù)結(jié)構(gòu)。 文中的內(nèi)容主要是來自于阮一峰的《ES6標(biāo)準(zhǔn)入門》(第三版)。《學(xué)習(xí)ES6筆記──工作中常用到的ES6語法》只是簡(jiǎn)單提及Set和Map,今天有空于是寫了這篇文章──《深入理解:ES6中的Set和Map數(shù)據(jù)結(jié)構(gòu),M...
摘要:創(chuàng)建并添加項(xiàng)目可以使用數(shù)組來初始化一個(gè),并且構(gòu)造器會(huì)確保不重復(fù)地使用這些值使用方法來測(cè)試某個(gè)值是否存在于中移除值使用方法來移除單個(gè)值,或調(diào)用方法來將所有值從中移除。屬性的初始化將數(shù)組傳遞給構(gòu)造器,以便使用數(shù)據(jù)來初始化一個(gè)。 主要知識(shí)點(diǎn):Set的基本操作,Weak Set,Map的基本操作,Weak MapshowImg(https://segmentfault.com/img/bVbf...
摘要:引入的數(shù)據(jù)結(jié)構(gòu)新加入的數(shù)據(jù)類型有這些數(shù)據(jù)結(jié)構(gòu)的支持并不廣泛,在寫這篇文章的時(shí)候。是或其他可枚舉的對(duì)象,其每個(gè)元素是的元數(shù)組。開頭的和不對(duì)持有引用,不影響。因此,他們沒有辦法對(duì)自身的進(jìn)行直接的枚舉。目前新版的和支持。 原文:http://pij.robinqu.me/JavaScript_Core/ECMAScript/es6/es6_data_types.html 源代...
摘要:中模擬與長(zhǎng)久以來,數(shù)組一直是中唯一的集合類型。用數(shù)組初始化集合事實(shí)上,只要是可迭代對(duì)象數(shù)組集合集合,都可以作為構(gòu)造函數(shù)的參數(shù)。構(gòu)造函數(shù)通過迭代器從參數(shù)中提取值。 ES5中模擬Set與Map 長(zhǎng)久以來,數(shù)組一直是JavaScript中唯一的集合類型。如果開發(fā)者們需要使用非數(shù)值型索引,就會(huì)用非數(shù)組對(duì)象創(chuàng)建所需的數(shù)據(jù)結(jié)構(gòu),而這就是Set集合與Map集合的早期實(shí)現(xiàn)。 一般來說,Set集合常被用...
摘要:提供了新的數(shù)據(jù)結(jié)構(gòu)。用法結(jié)構(gòu)有以下屬性構(gòu)造函數(shù),默認(rèn)就是函數(shù)。結(jié)構(gòu)有以下方法添加某個(gè)值,返回結(jié)構(gòu)本身。返回一個(gè)布爾值,表示該值是否為的成員。清除所有成員,沒有返回值。 Set ES6 提供了新的數(shù)據(jù)結(jié)構(gòu) Set。它類似于數(shù)組,但是成員的值都是唯一的,沒有重復(fù)的值。 用法:new Set([iterable]) const set = new Set([1, 2, 3, 4, 4, 4]...
摘要:由于和不會(huì)被轉(zhuǎn)換為字符串,所以在內(nèi)部是不同的項(xiàng),如果他們被轉(zhuǎn)化為字符串,那么都會(huì)等于,如果多次調(diào)用并傳入相同的值作為參數(shù)。第二次重復(fù)傳入并不會(huì)被添加到集合中,那么的屬性值還是為。的方法和共享了幾個(gè)方法。小結(jié)正式將與引入。 se5中的set與map 在est5中開發(fā)者使用對(duì)象屬性來模擬。set多用于檢查鍵的存在,map多用于提取數(shù)據(jù)。 { let set = Object.cre...
閱讀 2603·2023-04-25 19:31
閱讀 2329·2021-11-04 16:11
閱讀 2884·2021-10-08 10:05
閱讀 1596·2021-09-30 09:48
閱讀 2422·2019-08-30 15:56
閱讀 2475·2019-08-30 15:56
閱讀 2235·2019-08-30 15:53
閱讀 2342·2019-08-30 15:44