WeakMap features
Basic Concepts of WeakMap
WeakMap is a new collection type introduced in ECMAScript 6, similar to Map but with some key differences. WeakMap only accepts objects as keys (excluding null), and these keys are weakly referenced. This means that when the key object is no longer referenced elsewhere, it will be automatically reclaimed by the garbage collection mechanism.
const weakMap = new WeakMap();
const obj = {};
weakMap.set(obj, 'value');
console.log(weakMap.get(obj)); // Output: 'value'
Differences Between WeakMap and Map
WeakMap has several important differences compared to a regular Map:
- WeakMap keys must be objects, whereas Map can use any value as a key
- WeakMap keys are weakly referenced and do not prevent garbage collection
- WeakMap is not enumerable, has no
size
property, and lacks aclear()
method - WeakMap does not implement iterator methods like
keys()
,values()
, andentries()
// Map example
const map = new Map();
map.set('key', 'value');
console.log(map.size); // Output: 1
// WeakMap example
const weakMap = new WeakMap();
weakMap.set({}, 'value');
// console.log(weakMap.size); // Error: weakMap.size is undefined
WeakMap API Methods
WeakMap provides the following basic operation methods:
set(key, value)
: Sets a key-value pairget(key)
: Retrieves the value associated with a keyhas(key)
: Checks if a key existsdelete(key)
: Deletes the specified key-value pair
const weakMap = new WeakMap();
const key1 = {};
const key2 = {};
weakMap.set(key1, 'value1');
console.log(weakMap.has(key1)); // true
console.log(weakMap.get(key1)); // 'value1'
weakMap.delete(key1);
console.log(weakMap.has(key1)); // false
Weak Reference Feature of WeakMap
The most notable feature of WeakMap is its weak reference characteristic. When a key object in WeakMap is no longer referenced elsewhere, it will be garbage collected, even if WeakMap still retains a reference to it.
let obj = { id: 1 };
const weakMap = new WeakMap();
weakMap.set(obj, 'some value');
console.log(weakMap.has(obj)); // true
// Remove the reference to obj
obj = null;
// After garbage collection, the entry in weakMap will be automatically cleared
// Note: We cannot directly observe this because WeakMap does not provide methods for iteration or size checking
Use Cases for WeakMap
WeakMap is particularly suitable for the following scenarios:
- Private Data Storage: Can be used to store private data for objects; when the object is destroyed, the associated data is automatically cleared
- Cache Systems: Build caches that do not prevent garbage collection
- DOM Element Metadata: Store metadata associated with DOM elements
// Private data storage example
const privateData = new WeakMap();
class Person {
constructor(name, age) {
privateData.set(this, { name, age });
}
getName() {
return privateData.get(this).name;
}
getAge() {
return privateData.get(this).age;
}
}
const person = new Person('Alice', 30);
console.log(person.getName()); // 'Alice'
// When person is garbage collected, its private data will also be automatically cleared
WeakMap and DOM Elements
WeakMap is ideal for storing data associated with DOM elements because when a DOM element is removed from the document, the related data is automatically cleared, preventing memory leaks.
const elementData = new WeakMap();
function trackElement(element) {
elementData.set(element, {
clicks: 0,
lastClicked: null
});
element.addEventListener('click', () => {
const data = elementData.get(element);
data.clicks++;
data.lastClicked = new Date();
console.log(`Element clicked ${data.clicks} times`);
});
}
const button = document.createElement('button');
button.textContent = 'Click me';
document.body.appendChild(button);
trackElement(button);
// When the button is removed from the DOM and garbage collected, its associated data will also be automatically cleared
Performance Considerations for WeakMap
Due to its special nature, WeakMap is more efficient than Map in certain scenarios:
- Does not prevent key objects from being garbage collected, reducing memory usage
- When key objects are reclaimed, related entries are automatically deleted without manual cleanup
- Suitable for storing large amounts of temporary data, especially data tied to object lifecycles
// Performance test example
const testCount = 1000000;
const objects = [];
const weakMap = new WeakMap();
console.time('WeakMap set');
for (let i = 0; i < testCount; i++) {
const obj = {};
objects.push(obj);
weakMap.set(obj, i);
}
console.timeEnd('WeakMap set');
// Clear references
objects.length = 0;
// At this point, entries in weakMap will be garbage collected
Limitations of WeakMap
WeakMap also has some usage limitations to be aware of:
- Not enumerable; cannot retrieve all keys or values
- No
size
property; cannot determine how many entries are stored - Keys must be objects; primitive values cannot be used
- In most JavaScript engines, WeakMap is slower than Map
const weakMap = new WeakMap();
// The following operations will all cause errors
// console.log(weakMap.size);
// for (let key of weakMap) {}
// weakMap.forEach(...);
Practical Application Examples of WeakMap
A common practical application is implementing private members for objects. Before ES6, JavaScript lacked true private members, and WeakMap provides a solution.
const privateMembers = new WeakMap();
class BankAccount {
constructor(balance) {
privateMembers.set(this, {
balance: balance || 0
});
}
deposit(amount) {
const data = privateMembers.get(this);
data.balance += amount;
return data.balance;
}
withdraw(amount) {
const data = privateMembers.get(this);
if (amount > data.balance) {
throw new Error('Insufficient funds');
}
data.balance -= amount;
return data.balance;
}
getBalance() {
return privateMembers.get(this).balance;
}
}
const account = new BankAccount(100);
console.log(account.getBalance()); // 100
account.deposit(50);
console.log(account.getBalance()); // 150
// Cannot directly access private members
// console.log(account.balance); // undefined
WeakMap and Memory Management
An important advantage of WeakMap is that it does not prevent key objects from being garbage collected, making it very useful in memory-sensitive applications.
// Memory management example
function createLargeObjects() {
const weakMap = new WeakMap();
for (let i = 0; i < 10000; i++) {
const largeObj = new Array(10000).fill('data');
weakMap.set(largeObj, `metadata-${i}`);
// No reference to largeObj is retained; it will be garbage collected
}
}
createLargeObjects();
// All largeObj instances will be garbage collected; WeakMap will not prevent this
Browser Compatibility for WeakMap
WeakMap is widely supported in modern browsers but may not be supported in some older versions. Polyfills or transpilers like Babel can be used to provide support.
Browser | Supported Versions |
---|---|
Chrome | 36+ |
Firefox | 6+ |
Safari | 8+ |
Edge | 12+ |
Internet Explorer | 11+ |
// Detect WeakMap support
if (typeof WeakMap !== 'function') {
console.log('WeakMap is not supported in this environment');
// A polyfill can be used
}
Advanced Usage of WeakMap
WeakMap can be combined with other ES6 features to implement more complex functionality. For example, combining it with Proxy can create an auto-clearing cache system.
const cache = new WeakMap();
function createCacheProxy(target) {
return new Proxy(target, {
get(obj, prop) {
if (!cache.has(obj)) {
cache.set(obj, {});
}
const objCache = cache.get(obj);
if (prop in objCache) {
return objCache[prop];
}
const value = obj[prop];
if (typeof value === 'function') {
objCache[prop] = value.bind(obj);
} else {
objCache[prop] = value;
}
return objCache[prop];
}
});
}
class ExpensiveOperations {
compute() {
console.log('Performing expensive computation...');
return Math.random();
}
}
const obj = new ExpensiveOperations();
const proxy = createCacheProxy(obj);
console.log(proxy.compute()); // Performs computation
console.log(proxy.compute()); // Returns from cache
// When obj is garbage collected, its cache will also be automatically cleared
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn