代码之家  ›  专栏  ›  技术社区  ›  Terry

weakmap中使用dom节点作为密钥

  •  1
  • Terry  · 技术社区  · 6 年前

    使用时 WeakMap 我遇到了一个非常令人困惑的场景:假设我有一个包含一些要存储的数据的dom节点,并将其存储在 弱映射 使用元素/节点本身作为键,使用任意数据作为值。

    在存储和检索条目之间 弱映射 ,DOM节点已更改:例如, id 属性已更新。我希望 .get(<Node>) 会回来的 undefined 因为节点已经发生了变异,但是它仍然以某种方式返回它。

    但是,当我销毁DOM树中的节点并在不更改其任何属性或属性的情况下重新呈现它时,它现在被认为是 弱映射 储存时。

    我的问题是:为什么要在 弱映射 ,不返回 未定义 ?下面是一个概念证明示例,其中包含复制行为的说明:

    1. 点击“存储元素”
    2. 单击“检索元素”以验证元素是否确实存储在 弱映射
    3. 点击“突变元素”。元素应该具有 身份证件 属性已更新。
    4. 点击“检索元素”:即使元素已经变异,它仍然可以检索原始元素设置的值。
    5. 单击“销毁并重新创建元素”。节点将从DOM中移除,其 outerHTML 用于创建外观相同的元素。
    6. 点击“检索元素”: 弱映射 正确地报告找不到任何东西,因为我们使用一个全新的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 回复  |  直到 6 年前
        1
  •  2
  •   Ben West    6 年前

    同样的原因 {} !== {} ;两个对象具有相同的属性并不重要,或者如果两个对象发生了变化,只不过它们实际上是同一个对象——从技术上讲,是内存中相同的位置。如果要按属性和值比较对象,请使用像lodash中那样的深度相等函数。