【问题标题】:Destructured object loses reference after being modified解构对象在修改后丢失引用
【发布时间】:2019-09-06 21:27:06
【问题描述】:

赋值后对象引用丢失。任何以前的参考都不再相关。

我有以下几点:

// lib.js

const obj = { prop: { data: { some: 'empty' } } };

function loadObject() {
  obj.prop.data = { some: 'load' };
}

modules.exports = { prop: obj.prop, data: obj.prop.data, loadObject() };

// main.js

const { prop, data, loadObject } = require('./lib');

loadObject();

console.log(prop.data);    // data changed (new reference)
console.log(data);         // data not changed (old reference)

如何修改data 而不丢失其初始引用?

PS:

我有一堆文件导入这个库,它依赖于data。 我宁愿不将其替换为 prop.data 或在每个使用它的文件中重新读取它。

【问题讨论】:

    标签: javascript node.js commonjs


    【解决方案1】:

    您将data 替换为一个新对象。没有办法将引用旧对象的所有内容更改为指向新对象,因此如果您想保持完全相同的 API,您必须更改对象而不是替换它 - 可能就像您之前所做的那样:

    // if it’s a single property that’s the same before and after
    function loadObject() {
      obj.prop.data.some = 'load';
    }
    
    // if the properties before are a subset of the properties after
    function loadObject() {
      Object.assign(obj.prop.data, { some: 'load' });
    }
    
    // if you need to change the set of properties entirely
    function loadObject() {
      for (const key of Object.keys(obj.prop.data)) {
        delete obj.prop.data[key];
      }
    
      Object.assign(obj.prop.data, { some: 'load' });
    }
    

    【讨论】:

      【解决方案2】:

      该问题与不同的模块系统或对象解构无关。请看下面的例子。

      const obj = {prop: {data: {some: 'empty'}}};
      const objRef = obj.prop.data;
      
      console.log(objRef);
      
      obj.prop.data.some = 'not empty';
      
      console.log(objRef);
      
      obj.prop.data = {other: 'hello!'};
      
      console.log(objRef);
      
      console.log(obj);

      请记住,每次使用括号符号创建对象{} 时,您都在隐式实例化一个新的“独立”对象。这对于您示例中的嵌套对象仍然有效。实际上,您有多个对象的多个嵌套引用。

      嵌套对象的“名称”(父对象的键)充当一个变量,其中包含您正在使用 {} 实例化的新对象的引用。

      我知道这可能看起来令人困惑(因为确实如此),但如果您按照之前的 sn-p 进行操作,我相信您会明白的。 objRef 保留“独立”对象{some: 'empty'} 的引用,同时作为引用存储在所有其他对象中,直到主要对象obj。在这一行中:obj.prop.data = {other: 'hello!'}; 我们从主对象中完全删除了{some: 'empty'} 引用,但它保留在objRef 中,这将是该对象唯一剩余的引用。我们将objRefobj 分开。

      • 总结:

      每次使用{} -> 等价于 -> new Object()

      obj.prop.data.some = 'not empty'; -> 更改属性值。将在data: {} 对象的所有引用中看到。

      obj.prop.data = {other: 'hello!'}; -> 完全替换主对象中的data: {} 对象引用(破坏引用)(仍保留在objRef 中)。

      如果不清楚,我可以尝试用不同的方式解释。请告诉我。

      【讨论】:

        【解决方案3】:

        any 变量看似自行改变自己(就像图书馆的消费者会体验到的那样)是非常不直观的,并且通常被 linter 禁止,因为代码清晰 - 如果需要这种逻辑,请考虑导出一个返回当前数据的 函数,例如

        modules.exports = {
          prop: obj.prop,
          getData: () => obj.prop.data,
          loadObject
        };
        

        (请注意,要导出函数,您只需引用该函数,而不是调用它)

        虽然可能如果您使用的是 ES6 模块导出可变绑定,但这里不是这种情况,而且无论如何也不是一个好主意。

        【讨论】:

        • 在这里重新分配data 并没有改变module.exports.data,所以看起来它根本没有做任何事情。 (而且obj.data 不存在。)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-28
        相关资源
        最近更新 更多