深入理解JavaScript中的WeakMap

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-hant/n/303311.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-31 11:49
下一篇 2024-12-31 11:49

相關推薦

  • 使用JavaScript日期函數掌握時間

    在本文中,我們將深入探討JavaScript日期函數,並且從多個視角介紹其應用方法和重要性。 一、日期的基本表示與獲取 在JavaScript中,使用Date對象來表示日期和時間,…

    編程 2025-04-28
  • JavaScript中使用new Date轉換為YYYYMMDD格式

    在JavaScript中,我們通常會使用Date對象來表示日期和時間。當我們需要在網站上顯示日期時,很多情況下需要將Date對象轉換成YYYYMMDD格式的字符串。下面我們來詳細了…

    編程 2025-04-27
  • JavaScript中修改style屬性的方法和技巧

    一、基本概念和方法 style屬性是JavaScript中一個非常重要的屬性,它可以用來控制HTML元素的樣式,包括顏色、大小、字體等等。這裡介紹一些常用的方法: 1、通過Java…

    編程 2025-04-25
  • 深入解析Vue3 defineExpose

    Vue 3在開發過程中引入了新的API `defineExpose`。在以前的版本中,我們經常使用 `$attrs` 和` $listeners` 實現父組件與子組件之間的通信,但…

    編程 2025-04-25
  • CloneDeep函數在Javascript開發中的應用

    一、CloneDeep的概念 CloneDeep函數在Javascript中是一種深層克隆對象的方法,可以在拷貝對象時避免出現引用關係。使用者可以在函數中設置可選參數使其滿足多種拷…

    編程 2025-04-25
  • 深入理解byte轉int

    一、字節與比特 在討論byte轉int之前,我們需要了解字節和比特的概念。字節是計算機存儲單位的一種,通常表示8個比特(bit),即1字節=8比特。比特是計算機中最小的數據單位,是…

    編程 2025-04-25
  • JavaScript中的Object.getOwnPropertyDescriptors()

    一、簡介 Object.getOwnPropertyDescriptors()是JavaScript中一個非常有用的工具。簡單來說,這個方法可以獲取一個對象上所有自有屬性的屬性描述…

    編程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什麼是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一個內置小部件,它可以監測數據流(Stream)中數據的變…

    編程 2025-04-25
  • 深入探討OpenCV版本

    OpenCV是一個用於計算機視覺應用程序的開源庫。它是由英特爾公司創建的,現已由Willow Garage管理。OpenCV旨在提供一個易於使用的計算機視覺和機器學習基礎架構,以實…

    編程 2025-04-25
  • 深入了解scala-maven-plugin

    一、簡介 Scala-maven-plugin 是一個創造和管理 Scala 項目的maven插件,它可以自動生成基本項目結構、依賴配置、Scala文件等。使用它可以使我們專註於代…

    編程 2025-04-25

發表回復

登錄後才能評論