본문으로 건너뛰기

เนื้อหาภาษาไทย / 태국어 콘텐츠

시스템 가이드 검수 완료된 콘텐츠

WeakMap and WeakSet

บทความนี้แนะนำ `WeakMap` และ `WeakSet` ซึ่งเป็นโครงสร้างข้อมูลใน JavaScript ที่ต่างจาก `Map` และ `Set` ตรงที่การอ้างอิง (reference) ไปยัง keys/values เป็นแบบ "w...

WeakMap และ WeakSet ใน JavaScript: โครงสร้างข้อมูลที่ฉลาดกว่าที่คุณคิด

ในบทความก่อนหน้า เราได้สำรวจ Decorators ซึ่งเป็นคุณสมบัติที่ช่วยเพิ่มความสามารถในการปรับแต่งโค้ดของเราให้มีความยืดหยุ่นและ modular มากยิ่งขึ้น ในบทความนี้ เราจะมาดูกันที่โครงสร้างข้อมูลที่น่าสนใจอีกสองแบบใน JavaScript นั่นคือ WeakMap และ WeakSet ซึ่งมีความแตกต่างจาก Map และ Set ที่เราคุ้นเคยกันดี และมีประโยชน์อย่างยิ่งในการจัดการหน่วยความจำและการอ้างอิงอ็อบเจ็กต์อย่างมีประสิทธิภาพ

WeakMap vs. Map: ความแตกต่างที่การอ้างอิง

ทั้ง WeakMap และ Map เป็นโครงสร้างข้อมูลที่ใช้เก็บข้อมูลในรูปแบบ key-value pair แต่ความแตกต่างที่สำคัญที่สุดอยู่ที่การอ้างอิง (reference) ของ key

  • Map: เมื่อคุณเพิ่ม key เข้าไปใน Map, Map จะเก็บ reference ไปยัง key นั้นไว้ ซึ่งหมายความว่า key นั้นจะไม่ถูก garbage collected ตราบใดที่ Map ยังคงอยู่ แม้ว่าตัวแปรที่อ้างอิง key นั้นจากภายนอกจะถูกกำหนดให้เป็น null หรือไม่มีการอ้างอิงถึงอีกต่อไปก็ตาม
  • WeakMap: ในทางตรงกันข้าม WeakMap จะเก็บ key ในรูปแบบ "weakly held" ซึ่งหมายความว่าถ้าไม่มีการอ้างอิงถึง key นั้นจากที่อื่นอีกต่อไป (นอกเหนือจากใน WeakMap เอง) garbage collector จะสามารถ reclaim หน่วยความจำที่ key นั้นใช้ได้ แม้ว่า key นั้นจะยังคงอยู่ใน WeakMap ก็ตาม เมื่อ garbage collector ทำงานและ reclaim key นั้น, WeakMap จะลบ entry ที่เกี่ยวข้องกับ key นั้นออกโดยอัตโนมัติ

เหตุผลเชิงออกแบบ: การออกแบบ WeakMap มาในลักษณะนี้มีจุดประสงค์เพื่อป้องกัน memory leak ที่อาจเกิดขึ้นจากการอ้างอิงอ็อบเจ็กต์ที่ไม่จำเป็นไว้นานเกินไป โดยเฉพาะอย่างยิ่งในกรณีที่ key เป็นอ็อบเจ็กต์ DOM (Document Object Model) หรืออ็อบเจ็กต์ขนาดใหญ่อื่นๆ

ข้อจำกัดของ WeakMap: เนื่องจาก WeakMap อาศัย garbage collection ในการจัดการ key จึงมีข้อจำกัดบางประการ:

  • Key ต้องเป็นอ็อบเจ็กต์เท่านั้น (ไม่สามารถใช้ primitive types เช่น string หรือ number เป็น key ได้)
  • ไม่สามารถ iterate หรือตรวจสอบขนาดของ WeakMap ได้ (ไม่มี methods เช่น size, keys(), values(), entries()) เนื่องจากสถานะของ WeakMap อาจเปลี่ยนแปลงได้ตลอดเวลาจากการทำงานของ garbage collector

ตัวอย่างการใช้งาน:

let map = new Map();
let weakMap = new WeakMap();

let obj1 = { data: 'ข้อมูลสำคัญ' };
let obj2 = { data: 'ข้อมูลสำคัญ' };

map.set(obj1, 'ข้อมูลที่เกี่ยวข้องกับ obj1');
weakMap.set(obj2, 'ข้อมูลที่เกี่ยวข้องกับ obj2');

// obj1 ยังคงถูกอ้างอิงโดย map ดังนั้นจะไม่ถูก garbage collected
obj1 = null;
console.log(map.has(obj1)); // false (obj1 ถูกตั้งเป็น null แล้ว แต่ map ยังเก็บ reference เดิมไว้)
console.log(map.size); // 1 (ยังมี entry อยู่)

// obj2 ถูกตั้งเป็น null และไม่มีการอ้างอิงจากที่อื่นอีก
// obj2 จะถูก garbage collected ในอนาคต (ไม่สามารถระบุเวลาที่แน่นอนได้)
obj2 = null;
// weakMap.has(obj2) อาจจะ return false ในอนาคตหาก garbage collector ทำงาน
// weakMap.size จะไม่มีให้ใช้

WeakSet vs. Set: เช่นเดียวกับ Map

ความสัมพันธ์ระหว่าง WeakSet และ Set คล้ายคลึงกับ WeakMap และ Map

  • Set: เก็บ unique values และรักษา reference ไปยัง value นั้นไว้
  • WeakSet: เก็บ unique values ที่เป็นอ็อบเจ็กต์เท่านั้น และเก็บ reference ในรูปแบบ weakly held

เหตุผลเชิงออกแบบ: เช่นเดียวกับ WeakMap, WeakSet ถูกออกแบบมาเพื่อป้องกัน memory leak โดยอนุญาตให้ garbage collector reclaim หน่วยความจำที่อ็อบเจ็กต์ที่อยู่ใน WeakSet ใช้ หากไม่มีการอ้างอิงถึงอ็อบเจ็กต์นั้นจากที่อื่นอีก

ข้อจำกัดของ WeakSet:

  • Value ต้องเป็นอ็อบเจ็กต์เท่านั้น
  • ไม่สามารถ iterate หรือตรวจสอบขนาดของ WeakSet ได้ (ไม่มี methods เช่น size, values(), entries())

ตัวอย่างการใช้งาน:

let set = new Set();
let weakSet = new WeakSet();

let obj3 = { id: 1 };
let obj4 = { id: 2 };

set.add(obj3);
weakSet.add(obj4);

// obj3 ยังคงถูกอ้างอิงโดย set ดังนั้นจะไม่ถูก garbage collected
obj3 = null;
console.log(set.has(obj3)); // false (obj3 ถูกตั้งเป็น null แล้ว แต่ set ยังเก็บ reference เดิมไว้)
console.log(set.size); // 1 (ยังมี entry อยู่)

// obj4 ถูกตั้งเป็น null และไม่มีการอ้างอิงจากที่อื่นอีก
// obj4 จะถูก garbage collected ในอนาคต (ไม่สามารถระบุเวลาที่แน่นอนได้)
obj4 = null;
// weakSet.has(obj4) อาจจะ return false ในอนาคตหาก garbage collector ทำงาน
// weakSet.size จะไม่มีให้ใช้

Garbage Collection: กลไกการจัดการหน่วยความจำอัตโนมัติ

Garbage collection เป็นกระบวนการที่ JavaScript engine ใช้ในการ reclaim หน่วยความจำที่ถูกใช้โดยอ็อบเจ็กต์ที่ไม่ถูกใช้งานอีกต่อไป การทำงานของ garbage collector นั้นมีความซับซ้อนและขึ้นอยู่กับ implementation ของแต่ละ JavaScript engine แต่โดยทั่วไปแล้ว garbage collector จะทำงานโดยการ:

  1. Marking: เริ่มต้นจาก root objects (เช่น global object) และ traverse graph ของอ็อบเจ็กต์ที่อ้างอิงถึงกัน เพื่อ mark อ็อบเจ็กต์ที่ยังคงสามารถเข้าถึงได้
  2. Sweeping: Reclaim หน่วยความจำที่ถูกใช้โดยอ็อบเจ็กต์ที่ไม่ได้ถูก mark ไว้

WeakMap และ WeakSet ช่วยให้ garbage collector ทำงานได้อย่างมีประสิทธิภาพมากขึ้น โดยการบอก garbage collector ว่าอ็อบเจ็กต์ที่อยู่ใน WeakMap หรือ WeakSet นั้นไม่ควรถูกพิจารณาว่าเป็นอ็อบเจ็กต์ที่จำเป็นต้องเก็บรักษาไว้ หากไม่มีการอ้างอิงถึงอ็อบเจ็กต์นั้นจากที่อื่นอีก

แนวปฏิบัติที่ดีในการใช้งาน WeakMap และ WeakSet

  • ใช้ WeakMap และ WeakSet เมื่อต้องการเชื่อมโยงข้อมูลกับอ็อบเจ็กต์โดยไม่ต้องการป้องกัน garbage collection: ตัวอย่างเช่น การเก็บ metadata เกี่ยวกับอ็อบเจ็กต์ DOM หรือการเก็บแคชของผลลัพธ์ของการคำนวณที่เกี่ยวข้องกับอ็อบเจ็กต์
  • ระลึกถึงข้อจำกัดของ WeakMap และ WeakSet: ไม่สามารถ iterate หรือตรวจสอบขนาดได้ ดังนั้นจึงไม่เหมาะสำหรับการใช้งานที่ต้องการความสามารถเหล่านี้
  • พิจารณา alternative solutions หาก WeakMap และ WeakSet ไม่เหมาะสม: หากต้องการ iterate หรือตรวจสอบขนาด อาจจะต้องใช้ Map หรือ Set แทน และจัดการ memory leak ด้วยวิธีอื่น (เช่น การลบ references ที่ไม่จำเป็นออกด้วยตนเอง)

สรุป

WeakMap และ WeakSet เป็นเครื่องมือที่มีประโยชน์ในการจัดการหน่วยความจำและการอ้างอิงอ็อบเจ็กต์อย่างมีประสิทธิภาพใน JavaScript การทำความเข้าใจความแตกต่างระหว่าง WeakMap/WeakSet และ Map/Set จะช่วยให้คุณเขียนโค้ดที่ robust และป้องกัน memory leak ได้ดียิ่งขึ้น ในบทความถัดไป เราจะมาสำรวจ Typed Arrays ซึ่งเป็นโครงสร้างข้อมูลที่ช่วยให้เราทำงานกับ binary data ได้อย่างมีประสิทธิภาพมากขึ้น

Office.in.th Custom Service

이 구조를 바탕으로 시스템을 개발하거나 맞춤 변경하고 싶으신가요?

Office.in.th는 엔터프라이즈 웹 애플리케이션, API 연동, 공공/민간 업무 관리 시스템을 설계·개발하며 장기 지원을 제공합니다.

소프트웨어 개발 서비스 보기