在WeakMap中使用DOM节点作为键

时间:2018-08-07 22:24:57

标签: javascript weakmap

在使用WeakMap时,我遇到了一个令人费解的场景:假设我有一个DOM节点,其中包含一些我想存储的数据,然后我将其存储在WeakMap中元素/节点本身作为键,任意数据作为值。

在存储和从WeakMap检索条目之间,DOM节点已更改:假设id属性已更新。我希望.get(<Node>)将返回undefined,因为该节点已被突变,但是它仍然会以某种方式返回它。

但是,当我销毁DOM树中的节点并重新渲染该节点时-即使不更改其任何属性或属性-在存储它时,它现在仍被视为WeakMap中的新元素。

我的问题是:为什么在WeakMap中更改用作存储任意数据的键的DOM节点而不返回undefined?这是一个概念验证示例,其中包含重现行为的说明:

  1. 点击“商店元素”
  2. 单击“检索元素”以确认该元素确实存储在WeakMap
  3. 单击“更改元素”。元素应更新其id属性。
  4. 单击“检索元素”:即使该元素已发生突变,它仍然可以检索使用原始元素设置的值。
  5. 单击“销毁并重新创建元素”。从DOM中删除了该节点,并使用其outerHTML创建了外观相同的元素。
  6. 单击“检索元素”:WeakMap正确报告未找到任何内容,因为我们使用的是全新的DOM节点作为键。

const map = new WeakMap();

// Store element in WeakMap
document.getElementById('set').addEventListener('click', () => {
  const el = document.querySelector('#content > div');
  map.set(el, el.outerHTML);
  console.log('Element stored in WeakMap');
});

// Retrieve element from WeakMap
document.getElementById('get').addEventListener('click', () => {
  const el = document.querySelector('#content > div');
  const elHTML = map.get(el);
  if (elHTML)
    console.log(`Element found in WeakMap, it's data: ${elHTML}`);
  else
    console.log('Element not found in Weakmap!');
});

// Mutate the DOM node, let's say by giving it a new unique ID
let n = 0;
document.getElementById('mutate').addEventListener('click', () => {
  document.querySelector('#content > div').id = `test${n}`;
  console.log(`Element ID updated to: "test${n}"`);
  n++;
});

// Destroy and recreate element
document.getElementById('destroy_and_recreate').addEventListener('click', () => {
  const target = document.querySelector('#content > div');
  const targetHTML = target.outerHTML;
  target.remove();
  document.getElementById('content').innerHTML = targetHTML;
  console.log('Element destroyed and recreated');
});
<section id="content">
  <div id="test">Lorem ipsum dolor sit amet</div>
</section>
<hr />
<button type="button" id="set">Store element</button>
<button type="button" id="get">Retrieve element</button>
<hr />
<button type="button" id="mutate">Mutate element</button>
<button type="button" id="destroy_and_recreate">Destroy and recreate element</button>

1 个答案:

答案 0 :(得分:2)

{} !== {}相同的原因;两个对象具有相同的属性,或者是否更改了它们,仅取决于它们实际上是否是相同的对象(从技术上讲,在内存中的位置相同)并不重要。如果要按属性和值比较对象,请使用像Lodash中一样的深相等函数。