Javascript 在WeakMap中使用DOM节点作为键
在使用Javascript 在WeakMap中使用DOM节点作为键,javascript,weakmap,Javascript,Weakmap,在使用WeakMap时,我遇到了一个非常令人困惑的场景:假设我有一个DOM节点,其中包含一些我想要存储的数据,我使用元素/节点本身作为键,将任意数据作为值存储在WeakMap中 在从WeakMap存储和检索条目之间,DOM节点发生了变化:比如说,它的id属性被更新。我希望.get()将返回未定义的,因为节点已经发生了变异,但它仍然以某种方式返回它 但是,当我销毁DOM树中的节点并重新渲染它时,即使不更改它的任何属性或属性,它现在在存储时也被视为WeakMap中的新元素 我的问题是:为什么在Wea
WeakMap
时,我遇到了一个非常令人困惑的场景:假设我有一个DOM节点,其中包含一些我想要存储的数据,我使用元素/节点本身作为键,将任意数据作为值存储在WeakMap
中
在从WeakMap
存储和检索条目之间,DOM节点发生了变化:比如说,它的id
属性被更新。我希望.get()
将返回未定义的
,因为节点已经发生了变异,但它仍然以某种方式返回它
但是,当我销毁DOM树中的节点并重新渲染它时,即使不更改它的任何属性或属性,它现在在存储时也被视为WeakMap
中的新元素
我的问题是:为什么在WeakMap
中更改DOM节点(用作存储任意数据的键)时不返回undefined
?下面是一个概念验证示例,其中包含再现行为的说明:
WeakMap
id
属性outerHTML
用于创建外观相同的元素WeakMap
正确地报告没有找到任何内容,因为我们使用了一个全新的DOM节点作为键const map=new WeakMap();
//在WeakMap中存储元素
document.getElementById('set')。addEventListener('click',()=>{
const el=document.querySelector(“#content>div”);
地图集(el,el.outerHTML);
log('WeakMap中存储的元素');
});
//从WeakMap检索元素
document.getElementById('get').addEventListener('click',()=>{
const el=document.querySelector(“#content>div”);
const elHTML=map.get(el);
如果(elHTML)
log(`Element在WeakMap中找到,它的数据:${elHTML}`);
其他的
log('Weakmap!'中未找到元素!');
});
//改变DOM节点,比如说给它一个新的唯一ID
设n=0;
document.getElementById('mutate').addEventListener('click',()=>{
document.querySelector('#content>div').id=`test${n}`;
log(`Element ID更新为:“test${n}`);
n++;
});
//摧毁并重建元素
document.getElementById('destroy_and_recreate')。addEventListener('click',()=>{
const target=document.querySelector(“#content>div”);
const targetHTML=target.outerHTML;
target.remove();
document.getElementById('content').innerHTML=targetHTML;
log(“元素已销毁并重新创建”);
});代码>
Lorem ipsum dolor sit amet
存储元素
检索元素
变异元素
销毁并重新创建元素
的原因与{}!={}
;两个对象是否具有相同的属性并不重要,或者如果它们发生了更改,也不重要,重要的是它们是否实际上是相同的对象—从技术上讲,是内存中的相同位置。如果要按特性和值比较对象,请使用Lodash中的深度相等函数 为什么@charlietfl删除了他的答案,他基本上是正确的。基本上,DOM节点只是一个嵌套对象。当您更新属性时,您是在对其进行变异,而不是对其在内存中的位置进行变异。该对象需要可用于垃圾收集,以便WeakMap释放其密钥,从文档树中删除DOM会导致此问题。出于同样的原因,WeakMap键是不可枚举的:只是在前面的注释中添加了一个注释:从DOM树中删除元素不一定会将其标记为垃圾回收,只有当DOM树是该对象引用的唯一位置时才会出现这种情况。在remove&recreate示例中,两个元素对象是两个完全不同的实例。