WeakMap
åºçº¿
广æ³å¯ç¨
*
èª 2015å¹´7æ èµ·ï¼æ¤ç¹æ§å·²å¨ä¸»æµæµè§å¨ä¸å¾å°æ¯æï¼å¯å¨å¤§å¤æ°è®¾å¤åæµè§å¨çæ¬ä¸æ£å¸¸ä½¿ç¨ã
* æ¤ç¹æ§çæäºé¨åçæ¯æç¨åº¦å¯è½ææä¸åã
WeakMap æ¯ä¸ç§é®å¼å¯¹çéåï¼å
¶ä¸çé®å¿
é¡»æ¯å¯¹è±¡æéå
¨å±æ³¨åç符å·ï¼ä¸å¼å¯ä»¥æ¯ä»»æç JavaScript ç±»åï¼å¹¶ä¸ä¸ä¼å建对å®çé®ç强å¼ç¨ãæ¢å¥è¯è¯´ï¼ä¸ä¸ªå¯¹è±¡ä½ä¸º WeakMap çé®åå¨ï¼ä¸ä¼é»æ¢è¯¥å¯¹è±¡è¢«åå¾åæ¶ã䏿¦ä¸ä¸ªå¯¹è±¡ä½ä¸ºé®è¢«åæ¶ï¼é£ä¹å¨ WeakMap ä¸ç¸åºçå¼ä¾¿æä¸ºäºè¿è¡åå¾åæ¶çåé对象ï¼åªè¦å®ä»¬æ²¡æå
¶ä»çå¼ç¨åå¨ãå¯ä¸å¯ä»¥ä½ä¸º WeakMap çé®çåå§ç±»åæ¯éå
¨å±æ³¨åç符å·ï¼å 为éå
¨å±æ³¨åçç¬¦å·æ¯ä¿è¯å¯ä¸çï¼å¹¶ä¸ä¸è½è¢«éæ°å建ã
WeakMap å
è®¸å°æ°æ®ä¸å¯¹è±¡ç¸å
³èï¼èä¸é»æ¢é®å¯¹è±¡è¢«åå¾åæ¶ï¼å³ä½¿å¼å¼ç¨äºé®ãç¶èï¼WeakMap å¹¶ä¸å
许è§å¯å
¶é®ççå½å¨æï¼è¿å°±æ¯ä¸ºä»ä¹å®ä¸å
许æä¸¾ï¼å¦æ WeakMap æä¾äºä»»ä½è·å¾å
¶é®çåè¡¨çæ¹æ³ï¼é£ä¹è¿äºå表å°ä¼ä¾èµäºåå¾åæ¶çç¶æï¼è¿å¼å
¥äºä¸ç¡®å®æ§ãå¦æä½ æ³è¦å¯ä»¥è·åé®çå表ï¼ä½ åºè¯¥ä½¿ç¨ Map è䏿¯ WeakMapã
ä½ å¯ä»¥å¨å¸¦é®çéåæåç WeakMap 对象é¨åäºè§£æ´å¤å
³äº WeakMap çå
容ã
æè¿°
WeakMap çé®å¿ é¡»æ¯å¯è¢«åå¾åæ¶çã大夿°åå§æ°æ®ç±»åå¯ä»¥ä»»æå°è¢«å建ï¼ä¸æ²¡æçå½å¨æï¼å æ¤ä¸è½ä½ä¸ºé®ã对象åéå ¨å±æ³¨åç符å·é½å¯ä»¥ä½ä¸ºé®ï¼å 为å®ä»¬æ¯å¯è¢«åå¾åæ¶çã
WeakMap çæä¹
å¨ JavaScript éï¼map API å¯ä»¥éè¿ä½¿å ¶å个 API æ¹æ³å ±ç¨ä¸¤ä¸ªæ°ç»ï¼ä¸ä¸ªåæ¾é®ï¼ä¸ä¸ªåæ¾å¼ï¼æ¥å®ç°ãç»è¿ç§æ å°è®¾ç½®å¼æ¶ä¼åæ¶å°é®å弿·»å å°è¿ä¸¤ä¸ªæ°ç»çæ«å°¾ãä»è使å¾é®åå¼çç´¢å¼å¨ä¸¤ä¸ªæ°ç»ä¸ç¸å¯¹åºãå½ä»è¯¥æ å°åå¼çæ¶åï¼éè¦éåææçé®ï¼ç¶å使ç¨ç´¢å¼ä»åå¨å¼çæ°ç»ä¸æ£ç´¢åºç¸åºçå¼ã
ä½è¿æ ·çå®ç°ä¼æä¸¤ä¸ªå¾å¤§ç缺ç¹ï¼
- é¦å
èµå¼åæç´¢æä½é½æ¯
O(n)çæ¶é´å¤æåº¦ï¼n æ¯é®å¼å¯¹ç个æ°ï¼ï¼å 为è¿ä¸¤ä¸ªæä½é½éè¦éåå ¨é¨æ´ä¸ªæ°ç»æ¥è¿è¡å¹é ã - å¦å¤ä¸ä¸ªç¼ºç¹æ¯å¯è½ä¼å¯¼è´å åæ³æ¼ï¼å 为æ°ç»ä¼ä¸ç´å¼ç¨çæ¯ä¸ªé®åå¼ãè¿ç§å¼ç¨ä½¿å¾åå¾åæ¶ç®æ³ä¸è½åæ¶å¤çä»ä»¬ï¼å³ä½¿æ²¡æå ¶ä»ä»»ä½å¼ç¨åå¨äºã
ç¸è¾ä¹ä¸ï¼WeakMap çé®å¯¹è±¡ä¼å¼ºå¼ç¨å
¶å¼ï¼ç´å°è¯¥é®å¯¹è±¡è¢«åå¾åæ¶ï¼ä½ä»é£æ¶èµ·ï¼å®ä¼å为弱å¼ç¨ãå æ¤ï¼WeakMapï¼
- ä¸ä¼é»æ¢åå¾åæ¶ï¼ç´å°åå¾åæ¶å¨ç§»é¤äºé®å¯¹è±¡çå¼ç¨
- ä»»ä½å¼é½å¯ä»¥è¢«åå¾åæ¶ï¼åªè¦å®ä»¬çé®å¯¹è±¡æ²¡æè¢«
WeakMap以å¤çå°æ¹å¼ç¨
å½å°é®æ å°å°ä¸é®ç¸å
³çä¿¡æ¯ï¼è该信æ¯ä»
å¨é®æªè¢«åå¾åæ¶çæ
åµä¸å
·æä»·å¼æ¶ï¼WeakMap æ¯ä¸ä¸ªç¹å«æç¨çæé ã
ä½å 为 WeakMap ä¸å
许è§å¯å
¶é®ççå½å¨æï¼æä»¥å
¶é®æ¯ä¸å¯æä¸¾çãæ²¡ææ¹æ³å¯ä»¥è·å¾é®çå表ã妿æçè¯ï¼è¯¥å表å°ä¼ä¾èµäºåå¾åæ¶çç¶æï¼è¿å¼å
¥äºä¸ç¡®å®æ§ãå¦æä½ æ³è¦å¯ä»¥è·å¾é®çå表ï¼ä½ åºè¯¥ä½¿ç¨ Mapã
æé 彿°
WeakMap()-
å建ä¸ä¸ªæ°ç
WeakMap对象ã
å®ä¾å±æ§
è¿äºå±æ§å¨ WeakMap.prototype ä¸å®ä¹ï¼å¹¶ä¸ç±ææ WeakMap å®ä¾æå
±äº«ã
WeakMap.prototype.constructor-
å建äºè¯¥å®ä¾å¯¹è±¡çæé 彿°ã对äº
WeakMapå®ä¾ï¼åå§å¼æ¯WeakMapæé 彿°ã WeakMap.prototype[Symbol.toStringTag]-
[Symbol.toStringTag]屿§çåå§å¼æ¯å符串"WeakMap"ãè¯¥å±æ§å¨Object.prototype.toString()ä¸ä½¿ç¨ã
å®ä¾æ¹æ³
WeakMap.prototype.delete()-
å é¤ä»»ä½ä¸
keyå ³èçå¼ãå é¤ä¹åï¼WeakMap.prototype.has(key)å°ä¼è¿åfalseã WeakMap.prototype.get()-
è¿åä¸
keyå ³èçå¼ï¼å¦æä¸åå¨åè¿åundefinedã WeakMap.prototype.has()-
è¿åä¸ä¸ªå¸å°å¼ï¼æè¨æä¸ªå¼æ¯å¦å·²ç»ä¸
WeakMap对象ä¸çkeyå ³èã WeakMap.prototype.set()-
ç»
WeakMap对象ä¸çkey设置valueãè¿å该WeakMap对象ã
示ä¾
>ä½¿ç¨ WeakMap
const wm1 = new WeakMap();
const wm2 = new WeakMap();
const wm3 = new WeakMap();
const o1 = {};
const o2 = function () {};
const o3 = window;
wm1.set(o1, 37);
wm1.set(o2, "azerty");
wm2.set(o1, o2); // value å¯ä»¥æ¯ä»»æå¼ï¼å
æ¬ä¸ä¸ªå¯¹è±¡æä¸ä¸ªå½æ°
wm2.set(o2, undefined);
wm2.set(wm1, wm2); // é®åå¼å¯ä»¥æ¯ä»»æå¯¹è±¡ï¼çè³å¦å¤ä¸ä¸ª WeakMap 对象
wm1.get(o2); // "azerty"
wm2.get(o2); // undefinedï¼è®¾ç½®çå¼å°±æ¯ undefined
wm2.get(o3); // undefinedï¼wm2 䏿²¡æ o3 è¿ä¸ªé®
wm1.has(o2); // true
wm2.has(o2); // trueï¼å³ä½¿å¼æ¯ undefinedï¼
wm2.has(o3); // false
wm3.set(o1, 37);
wm3.get(o1); // 37
wm1.has(o1); // true
wm1.delete(o1);
wm1.has(o1); // false
å®ç°ä¸ä¸ªå¸¦æ .clear() æ¹æ³çç±» WeakMap çç±»
class ClearableWeakMap {
#wm;
constructor(init) {
this.#wm = new WeakMap(init);
}
clear() {
this.#wm = new WeakMap();
}
delete(k) {
return this.#wm.delete(k);
}
get(k) {
return this.#wm.get(k);
}
has(k) {
return this.#wm.has(k);
}
set(k, v) {
this.#wm.set(k, v);
return this;
}
}
模æç§ææå
å¼åè
å¯ä»¥ä½¿ç¨ WeakMap å
³è对象ä¸ç§ææ°æ®ï¼ä»èè·å¾ä»¥ä¸å¥½å¤ï¼
- ä¸
Mapç¸æ¯ï¼WeakMap 䏿æé®å¯¹è±¡ç强å¼ç¨ï¼å æ¤å æ°æ®ä¸å¯¹è±¡æ¬èº«å ±äº«åæ ·ççå½å¨æï¼é¿å å åæ³æ¼ã - ä¸ä½¿ç¨ä¸å¯æä¸¾å¯¹è±¡å/æ
Symbol屿§ç¸æ¯ï¼WeakMap ä½äºå¯¹è±¡å¤é¨ï¼æ²¡æåæ³éè¿åObject.getOwnPropertySymbolsççåå°æ¹æ³æ¥æ£ç´¢å æ°æ®ã - ä¸éå ç¸æ¯ï¼æé 彿°å¯ä»¥å¤ç¨åä¸ä¸ª WeakMap 对象æ¥å建ææå®ä¾ï¼ä»èèçå åï¼å¹¶ä¸å 许åä¸ä¸ªç±»å建çä¸åå®ä¾è¯»åå½¼æ¤çç§ææåã
let Thing;
{
const privateScope = new WeakMap();
let counter = 0;
Thing = function () {
this.someProperty = "foo";
privateScope.set(this, {
hidden: ++counter,
});
};
Thing.prototype.showPublic = function () {
return this.someProperty;
};
Thing.prototype.showPrivate = function () {
return privateScope.get(this).hidden;
};
}
console.log(typeof privateScope);
// "undefined"
const thing = new Thing();
console.log(thing);
// Thing {someProperty: "foo"}
thing.showPublic();
// "foo"
thing.showPrivate();
// 1
è¿ä¸ä¸é¢ä½¿ç¨äºç§æå段ç示ä¾ç±»ä¼¼ï¼
class Thing {
static #counter = 0;
#hidden;
constructor() {
this.someProperty = "foo";
this.#hidden = ++Thing.#counter;
}
showPublic() {
return this.someProperty;
}
showPrivate() {
return this.#hidden;
}
}
console.log(thing);
// Thing {someProperty: "foo"}
thing.showPublic();
// "foo"
thing.showPrivate();
// 1
å ³èå æ°æ®
WeakMap å¯ç¨äºå°å
æ°æ®ä¸å¯¹è±¡å
³èï¼èä¸å½±å对象ççå½å¨æãè¿ä¸ç§ææå示ä¾é常ç¸ä¼¼ï¼å ä¸ºç§ææå乿¯ä»¥å¤é¨ç形弿¨¡æçå
æ°æ®ï¼ä¸åä¸ååç»§æ¿ã
è¿ä¸ªç¨ä¾å¯ä»¥æ©å±å°å·²ç»å建ç对象ä¸ãä¾å¦ï¼å¨ç½é¡µä¸ï¼æä»¬å¯è½å¸æå°é¢å¤çæ°æ®ä¸ DOM å ç´ ç¸å ³èï¼è DOM å ç´ å¯è½å¨ä¹å访é®è¿äºæ°æ®ãä¸ç§å¸¸è§çåæ³æ¯å°æ°æ®éå ä¸ºå±æ§ï¼
const buttons = document.querySelectorAll(".button");
buttons.forEach((button) => {
button.clicked = false;
button.addEventListener("click", () => {
button.clicked = true;
const currentButtons = [...document.querySelectorAll(".button")];
if (currentButtons.every((button) => button.clicked)) {
console.log("æææé®è¢«é½è¢«ç¹å»äºï¼");
}
});
});
è¿ç§æ¹æ³æ¯ææçï¼ä½æ¯æä¸äºç¼ºç¹ï¼
clicked屿§æ¯å¯æä¸¾çï¼å æ¤å®ä¼åºç°å¨Object.keys(button)ãfor...in循ç¯ä¸ï¼ççãå¯ä»¥éè¿ä½¿ç¨Object.defineProperty()æ¥ç¼è§£ï¼ä½è¿ä¼ä½¿ä»£ç æ´åé¿ãclicked屿§æ¯ä¸ä¸ªæ®éçåç¬¦ä¸²å±æ§ï¼å æ¤å®å¯ä»¥è¢«å ¶ä»ä»£ç 访é®åè¦çãå¯ä»¥éè¿ä½¿ç¨Symbol鮿¥ç¼è§£ï¼ä½é®ä»ç¶å¯ä»¥éè¿Object.getOwnPropertySymbols()访é®ã
ä½¿ç¨ WeakMap æ¥è§£å³è¿äºé®é¢ï¼
const buttons = document.querySelectorAll(".button");
const clicked = new WeakMap();
buttons.forEach((button) => {
clicked.set(button, false);
button.addEventListener("click", () => {
clicked.set(button, true);
const currentButtons = [...document.querySelectorAll(".button")];
if (currentButtons.every((button) => clicked.get(button))) {
console.log("æææé®è¢«é½è¢«ç¹å»äºï¼");
}
});
});
è¿æ®µä»£ç éï¼åªæè½è®¿é® clicked çä»£ç æè½ç¥éæ¯ä¸ªæé®çç¹å»ç¶æï¼èå¤é¨ä»£ç å°±ä¸è½ä¿®æ¹è¿äºç¶æãæ¤å¤ï¼å¦æä»»ä½æé®ä» DOM ä¸å é¤ï¼é£ä¹ç¸åºçå
æ°æ®å°èªå¨è¿è¡åå¾åæ¶ã
ç¼å
ä½ å¯ä»¥å°ä¼ éç»å½æ°ç对象ä¸å½æ°çç»æç¸å ³èï¼ä»èå¨åæ¬¡ä¼ å ¥ç¸åç对象æ¶ï¼å¯ä»¥è¿åç¼åçç»æèæ é忬¡æ§è¡å½æ°ãå¦æè¯¥å½æ°æ¯çº¯å½æ°ï¼å³å®ä¸ä¼æ¹åä»»ä½å¤é¨å¯¹è±¡æå¯¼è´å ¶ä»å¯è§å¯å°çå¯ä½ç¨ï¼çè¯ï¼è¿é常æç¨ã
const cache = new WeakMap();
function handleObjectValues(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = Object.values(obj).map(heavyComputation);
cache.set(obj, result);
return result;
}
åªæå½å½æ°çè¾å
¥æ¯å¯¹è±¡æ¶æææãæ¤å¤ï¼å³ä½¿è¾å
¥ä¸åä¼ å
¥ï¼ç»æä¾ç¶æ°¸è¿ä¿çå¨ç¼åä¸ï¼æ´ææçæ¹æ³æ¯å° Map ä¸ WeakRef 对象é
对使ç¨ï¼è¿å
è®¸ä½ å°ä»»ä½ç±»åçè¾å
¥å¼ä¸åèªçï¼å¾å¯è½çï¼è®¡ç®ç»æå
³èãæå
³æ´å¤è¯¦ç»ä¿¡æ¯ï¼è¯·åé
WeakRef å FinalizationRegistry 示ä¾ã
è§è
| è§è |
|---|
| ECMAScript® 2027 Language Specification> # sec-weakmap-objects> |
æµè§å¨å ¼å®¹æ§
åè§
core-jsä¸WeakMapç polyfill- 带é®çéå
- ä½¿ç¨ ECMAScript 6 WeakMap éèå®ç°ç»èï¼ä½è ï¼å°¼å ·è²è¨æ°æå¾·ï¼2014ï¼
MapSetWeakSet