WeakMap是ES2015中新增的一種集合類型,它的設計目標是提供一種弱引用的數據結構,它的主要用途是用於實現一些對垃圾回收模型敏感的功能,比如緩存、事件監聽等。本文將從多個方面來詳細講解WeakMap的特性和使用場景。
一、什麼是WeakMap
首先,我們需要了解什麼是Map。Map是一種使用鍵值對儲存數據的集合類型,其中鍵和值可以是任何類型(包括引用類型),並且可以使用for…of循環進行遍歷。與之相對的WeakMap則是一種只能使用對象作為鍵的集合類型,而且對象鍵對應的對象值只能通過對象本身來訪問,無法通過其他方式訪問。
const map = new Map();
const obj1 = {name: "John"};
const obj2 = {name: "Lucy"};
map.set(obj1, "Hello");
map.set(obj2, "World");
console.log(map.get(obj1)); // "Hello"
console.log(map.get(obj2)); // "World"
const weakMap = new WeakMap();
const obj3 = {};
const obj4 = {};
weakMap.set(obj3, "Hello");
weakMap.set(obj4, "World");
console.log(weakMap.get(obj3)); // "Hello"
console.log(weakMap.get(obj4)); // "World"
可以看到,WeakMap可以像Map一樣儲存鍵值對,不同之處是WeakMap的鍵只能是對象,並且這些對象鍵所對應的值只能通過這些對象本身來訪問,不能像Map一樣通過鍵本身來訪問。
二、WeakMap的弱引用特性
WeakMap之所以被稱為「弱引用」,是因為它的鍵實際上是一種弱引用。在JavaScript中,內存管理是由垃圾回收器來負責的,而垃圾回收器的主要判斷依據就是對象是否被引用。如果一個對象沒有被任何引用所引用,那麼它就會被判定為垃圾對象,並被回收。
在WeakMap中,如果一個鍵對應的對象被回收了,那麼這個鍵所對應的鍵值對也會被自動刪除。這意味著,如果使用WeakMap來儲存一些內存佔用較大的對象,當這些對象不再被引用時,它們也會被自動回收,從而釋放內存空間。
const weakMap = new WeakMap();
(function() {
const obj = {name: "John"};
weakMap.set(obj, "Hello");
})();
// obj被回收了,對應的鍵值對也被刪除了
console.log(weakMap.size); // undefined
在上面的代碼中,我們使用立即執行函數來創建一個包含一個對象的作用域,在這個作用域中,我們將這個對象作為WeakMap的鍵儲存了起來,然後立即銷毀了這個作用域。由於obj對象在該作用域外沒有任何引用,因此它會被垃圾回收器判定為垃圾對象,並被自動回收。在這個過程中,WeakMap中對應的鍵值對也會被刪除。
三、常見應用場景
1. 實現私有屬性
在JavaScript中,沒有真正意義上的私有屬性。通過使用WeakMap,我們可以實現一種近似私有屬性的機制。我們可以利用WeakMap的弱引用特性,將某個實例對象作為鍵,將需要儲存的私有屬性作為鍵值儲存在WeakMap中。由於對該實例對象的引用僅存在於該實例對象本身中,因此除了該實例對象本身,沒有任何其他途徑可以訪問到其對應的私有屬性。
const privateData = new WeakMap();
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
privateData.set(this, {salary: 5000});
}
getSalary() {
return privateData.get(this).salary;
}
}
const person = new Person("John", 20);
console.log(person.name); // "John"
console.log(person.getSalary()); // 5000
console.log(privateData.get(person)); // undefined
2. 緩存
緩存是一種常見的技術,用於提高程序的運行效率。由於WeakMap的弱引用特性,我們可以在不佔用過多內存的前提下實現緩存功能。我們可以將某個需要緩存的對象作為鍵,將它的計算結果作為鍵值儲存在WeakMap中。在後續使用時,我們可以根據需要重新計算並存入WeakMap中,這可以避免緩存造成的內存佔用問題。
const cache = new WeakMap();
function factorial(n) {
if(n === 0) {
return 1;
}
if(cache.has(n)) {
console.log("Cache hit!");
return cache.get(n);
}
const result = n * factorial(n - 1);
cache.set(n, result);
console.log("Cache miss!");
return result;
}
console.log(factorial(5)); // Cache miss! 120
console.log(factorial(5)); // Cache hit! 120
3. 存儲DOM節點相關數據
在JavaScript中,我們可以使用dataset屬性或者一些自定義屬性來實現存儲一些與Dom節點相關的數據,但是這會引發一些垃圾回收方面的問題。使用WeakMap來儲存這些數據,則可以避免這些問題。
const nodeCache = new WeakMap();
function setAttribute(node, name, value) {
if(!nodeCache.has(node)) {
nodeCache.set(node, {});
}
nodeCache.get(node)[name] = value;
}
function getAttribute(node, name) {
return nodeCache.has(node) ? nodeCache.get(node)[name] : undefined;
}
const div = document.createElement("div");
setAttribute(div, "data-name", "John");
console.log(getAttribute(div, "data-name")); // "John"
四、總結
本文詳細介紹了JavaScript中的WeakMap,並從WeakMap的定義、弱引用特性、常見應用場景等多個方面進行了闡述。希望讀者們可以通過本文更深入地了解JavaScript的集合類型之一的弱引用集合。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/303311.html