解构对象在修改后丢失引用

Destructured object loses reference after being modified

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

我有以下内容:

// 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 或在每个使用它的文件中重新阅读它。

任何变量看似改变自己自己(作为图书馆的消费者会体验到)是非常不直观的,并且是为了代码清晰起见,经常被 linters 禁止 - 如果需要那种逻辑,请考虑导出 函数 而 returns 当前数据,例如

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

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

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

您用新对象替换了 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' });
}

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

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);

请记住,每次使用括号表示法创建对象时 {} 您都在隐式实例化一个新的 "independent" 对象。这对于您示例中的嵌套对象仍然有效。事实上,您有多个对象的多个嵌套引用。

嵌套对象的'name'(父对象的键)充当一个变量,其中包含您使用{}实例化的新对象的引用。

我知道这可能看起来令人困惑(因为它确实如此),但如果您按照前面的代码片段进行操作,我相信您会明白的。 objRef 保留 "independent" 对象 {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 中)。

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