เมื่อดูสิ่งนี้และหน้า MDN นี้ดูเหมือนว่าข้อแตกต่างเพียงอย่างเดียวระหว่าง Maps และ WeakMaps คือคุณสมบัติ "ขนาด" ที่ขาดหายไปสำหรับ WeakMaps แต่นี่เป็นเรื่องจริงหรือไม่? อะไรคือความแตกต่างระหว่างพวกเขา?
key
ไม่สามารถรวบรวมได้เนื่องจากคุณอ้างถึง
key
ไม่สามารถรวบรวมได้เนื่องจากคุณอ้างถึง
คำตอบ:
จากหน้าเดียวกันส่วน " Why Weak Map? " :
โปรแกรมเมอร์ JavaScript ที่มีประสบการณ์จะสังเกตเห็นว่า API นี้สามารถใช้งานได้ใน JavaScript โดยมีสองอาร์เรย์ (อันหนึ่งสำหรับคีย์หนึ่งสำหรับค่า) ที่ใช้ร่วมกันโดย 4 เมธอด API การดำเนินการดังกล่าวจะมีความไม่สะดวกหลักสองประการ อันแรกคือการค้นหา O (n) (n เป็นจำนวนปุ่มในแผนที่) อย่างที่สองคือปัญหาหน่วยความจำรั่ว ด้วยแผนที่ที่เขียนด้วยตนเองอาร์เรย์ของคีย์จะเก็บข้อมูลอ้างอิงไปยังวัตถุสำคัญป้องกันไม่ให้ถูกเก็บรวบรวมขยะ ใน WeakMaps ดั้งเดิมการอ้างอิงถึงออบเจ็กต์สำคัญจะมีลักษณะ"อย่างอ่อน"ซึ่งหมายความว่าพวกเขาไม่ได้ป้องกันการรวบรวมขยะในกรณีที่ไม่มีการอ้างอิงอื่น ๆ ไปยังวัตถุ
เนื่องจากการอ้างอิงอ่อนแอคีย์ WeakMap จึงไม่สามารถนับได้ (กล่าวคือไม่มีวิธีใดที่ให้รายการคีย์แก่คุณ) หากเป็นเช่นนั้นรายการจะขึ้นอยู่กับสถานะของการเก็บขยะโดยนำเสนอสิ่งที่ไม่ใช่ปัจจัย
[และนั่นคือสาเหตุที่พวกเขาไม่มีsize
ทรัพย์สินเช่นกัน]
หากคุณต้องการมีรายการคีย์คุณควรดูแลรักษาด้วยตัวเอง นอกจากนี้ยังมีข้อเสนอ ECMAScript ซึ่ง มีจุดมุ่งหมายเพื่อแนะนำชุดและแผนที่ง่ายๆซึ่งจะไม่ใช้การอ้างอิงที่ไม่รัดกุมและสามารถแจกแจงได้
- ซึ่งจะเป็น"ปกติ" s ไม่ได้กล่าวถึงที่ MDN แต่ในข้อเสนอสามัคคีเหล่านั้นยังมี, และวิธีการกำเนิดและใช้อินเตอร์เฟซMap
items
keys
values
Iterator
new Map().get(x)
มีเวลาในการค้นหาเช่นเดียวกับการอ่านคุณสมบัติจากวัตถุธรรมดาหรือไม่?
ทั้งสองทำงานแตกต่างกันเมื่อวัตถุที่อ้างอิงโดยคีย์ / ค่าของพวกเขาถูกลบ ให้ใช้โค้ดตัวอย่างด้านล่าง:
var map = new Map();
var weakmap = new WeakMap();
(function(){
var a = {x: 12};
var b = {y: 12};
map.set(a, 1);
weakmap.set(b, 2);
})()
IIFE ดังกล่าวข้างต้นจะถูกดำเนินการมีวิธีที่เราสามารถอ้างอิงไม่มี{x: 12}
และ{y: 12}
อีกต่อไป ตัวเก็บขยะจะดำเนินการต่อและลบตัวชี้คีย์ b จาก“ WeakMap” และลบออก{y: 12}
จากหน่วยความจำด้วย แต่ในกรณีของ“ แผนที่” ตัวเก็บขยะจะไม่ลบตัวชี้ออกจาก“ แผนที่” และไม่ได้ลบออก{x: 12}
จากหน่วยความจำด้วย
สรุป: WeakMap อนุญาตให้ตัวเก็บขยะทำงานได้ แต่ไม่ใช่แผนที่
ข้อมูลอ้างอิง: http://qnimate.com/difference-between-map-and-weakmap-in-javascript/
map.entries().next().value // [{x:12}, 1]
WeakMap
สามารถมีคีย์ที่ไม่ใช่แบบดั้งเดิมเท่านั้น (ไม่มีสตริงหรือตัวเลขหรือSymbol
s เป็นคีย์เฉพาะอาร์เรย์อ็อบเจ็กต์แผนที่อื่น ๆ ฯลฯ )
Map
แต่ไม่ใช่ในWeakMap
บางทีคำอธิบายต่อไปอาจชัดเจนสำหรับใครบางคน
var k1 = {a: 1};
var k2 = {b: 2};
var map = new Map();
var wm = new WeakMap();
map.set(k1, 'k1');
wm.set(k2, 'k2');
k1 = null;
map.forEach(function (val, key) {
console.log(key, val); // k1 {a: 1}
});
k2 = null;
wm.get(k2); // undefined
อย่างที่คุณเห็นหลังจากลบk1
คีย์ออกจากหน่วยความจำแล้วเรายังสามารถเข้าถึงมันได้ภายในแผนที่ ในขณะเดียวกันก็ลบk2
คีย์ของ WeakMap ออกwm
ด้วยเช่นกันโดยการอ้างอิง
นั่นเป็นเหตุผลที่ WeakMap ไม่มีวิธีการแจกแจงเช่น forEach เนื่องจากไม่มีรายการคีย์ WeakMap เป็นเพียงการอ้างอิงไปยังวัตถุอื่น
forEach
, (key, val)
ควรจะเป็นจริง(val, key)
ความแตกต่างอีกประการหนึ่ง (ที่มา: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap ):
คีย์ของ WeakMaps เป็นประเภท Object เท่านั้น ไม่อนุญาตให้ใช้ประเภทข้อมูลดั้งเดิมเป็นคีย์ (เช่น Symbol ไม่สามารถเป็นคีย์ WeakMap ได้)
ไม่สามารถใช้สตริงตัวเลขหรือบูลีนเป็นWeakMap
คีย์ได้ A Map
สามารถใช้ค่าดั้งเดิมสำหรับคีย์
w = new WeakMap;
w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key
m = new Map
m.set('a', 'b'); // Works
จากJavascript.info
แผนที่ - หากเราใช้วัตถุเป็นกุญแจสำคัญในแผนที่ปกติในขณะที่มีแผนที่วัตถุนั้นก็มีอยู่เช่นกัน มันใช้หน่วยความจำและอาจไม่เก็บขยะ
let john = { name: "John" };
let array = [ john ];
john = null; // overwrite the reference
// john is stored inside the array, so it won't be garbage-collected
// we can get it as array[0]
ในทำนองเดียวกันถ้าเราใช้วัตถุเป็นกุญแจสำคัญในแผนที่ปกติในขณะที่มีแผนที่วัตถุนั้นก็มีอยู่เช่นกัน มันใช้หน่วยความจำและอาจไม่เก็บขยะ
let john = { name: "John" };
let map = new Map();
map.set(john, "...");
john = null; // overwrite the reference
// john is stored inside the map,
// we can get it by using map.keys()
WeakMap - ตอนนี้ถ้าเราใช้วัตถุเป็นกุญแจสำคัญในนั้นและไม่มีการอ้างอิงอื่น ๆ ไปยังวัตถุนั้น - มันจะถูกลบออกจากหน่วยความจำ (และจากแผนที่) โดยอัตโนมัติ
let john = { name: "John" };
let weakMap = new WeakMap();
weakMap.set(john, "...");
john = null; // overwrite the reference
// john is removed from memory!
WeapMap ใน javascript ไม่ได้เก็บคีย์หรือค่าใด ๆ เพียงแค่ปรับแต่งค่าคีย์โดยใช้id เฉพาะและกำหนดคุณสมบัติให้กับคีย์
เพราะมันกำหนดคุณสมบัติการkey object
โดยวิธีการObject.definePropert()
, ที่สำคัญจะต้องไม่เป็นชนิดดั้งเดิม
และเนื่องจาก WeapMap ไม่มีคู่ค่าคีย์จริงเราจึงไม่สามารถรับคุณสมบัติความยาวของจุดอ่อนแผนที่ได้
และยังมีการกำหนดค่าที่ถูกจัดการกลับไปยังวัตถุหลักตัวเก็บขยะสามารถรวบรวมคีย์ได้อย่างง่ายดายหากไม่มีการใช้งาน
โค้ดตัวอย่างสำหรับการนำไปใช้งาน
if(typeof WeapMap != undefined){
return;
}
(function(){
var WeapMap = function(){
this.__id = '__weakmap__';
}
weakmap.set = function(key,value){
var pVal = key[this.__id];
if(pVal && pVal[0] == key){
pVal[1]=value;
}else{
Object.defineProperty(key, this.__id, {value:[key,value]});
return this;
}
}
window.WeakMap = WeakMap;
})();
การอ้างอิงการใช้งาน
id
แต่สิ่งนี้ควรจะไม่ซ้ำกันโดยใช้บางอย่าง Math.random และ Date.now () เป็นต้นและด้วยการเพิ่ม ID ไดนามิกนี้จุดแรกสามารถแก้ไขได้ คุณช่วยกรุณาให้วิธีแก้ปัญหาสำหรับสองจุดสุดท้าย
WeakMap
คีย์ต้องเป็นวัตถุไม่ใช่ค่าดั้งเดิม
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, "ok"); // works fine (object key)
// can't use a string as the key
weakMap.set("test", "Not ok"); // Error, because "test" is not an object
ทำไม????
ลองดูตัวอย่างด้านล่าง
let user = { name: "User" };
let map = new Map();
map.set(user, "...");
user = null; // overwrite the reference
// 'user' is stored inside the map,
// We can get it by using map.keys()
ถ้าเราใช้ออบเจ็กต์เป็นคีย์ในปกติ
Map
แล้วในขณะที่Map
มีอยู่อ็อบเจ็กต์นั้นก็มีอยู่เช่นกัน มันใช้หน่วยความจำและอาจไม่เก็บขยะ
WeakMap
มีความแตกต่างกันโดยพื้นฐานในด้านนี้ ไม่ได้ป้องกันการเก็บขยะของวัตถุสำคัญ
let user = { name: "User" };
let weakMap = new WeakMap();
weakMap.set(user, "...");
user = null; // overwrite the reference
// 'user' is removed from memory!
หากเราใช้วัตถุเป็นกุญแจสำคัญในนั้นและไม่มีการอ้างอิงอื่น ๆ ไปยังวัตถุนั้น - สิ่งนั้นจะถูกลบออกจากหน่วยความจำ (และจากแผนที่) โดยอัตโนมัติ
WeakMap
ไม่รองรับการทำซ้ำและคีย์วิธีการ() , ค่า () , รายการ ()ดังนั้นจึงไม่มีวิธีรับคีย์หรือค่าทั้งหมดจากคีย์นั้น
WeakMap มีเพียงวิธีการดังต่อไปนี้:
เห็นได้ชัดว่าหากวัตถุสูญเสียการอ้างอิงอื่น ๆ ทั้งหมด (เช่น 'ผู้ใช้' ในโค้ดด้านบน) จากนั้นจะถูกรวบรวมโดยอัตโนมัติ แต่ในทางเทคนิคไม่ได้ระบุไว้อย่างแน่นอนเมื่อการล้างข้อมูลเกิดขึ้น
เอ็นจิ้น JavaScript ตัดสินใจว่า อาจเลือกที่จะดำเนินการล้างหน่วยความจำทันทีหรือรอและทำความสะอาดในภายหลังเมื่อมีการลบเกิดขึ้นมากขึ้น ดังนั้นในทางเทคนิคWeakMap
จึงไม่ทราบจำนวนองค์ประกอบปัจจุบันของ a เครื่องยนต์อาจทำความสะอาดหมดแล้วหรือไม่หรือทำเพียงบางส่วน ด้วยเหตุนี้จึงไม่รองรับวิธีการเข้าถึงคีย์ / ค่าทั้งหมด
หมายเหตุ: -พื้นที่หลักของแอปพลิเคชันสำหรับ WeakMap คือพื้นที่จัดเก็บข้อมูลเพิ่มเติม เช่นเดียวกับการแคชวัตถุจนกว่าวัตถุนั้นจะได้รับขยะ