即使在删除原始属性后,通过引用复制到第二个属性的对象仍然存在?

Posted

技术标签:

【中文标题】即使在删除原始属性后,通过引用复制到第二个属性的对象仍然存在?【英文标题】:Object copied to second property via reference persists even after original property deleted? 【发布时间】:2014-12-22 09:40:57 【问题描述】:

我认为对象是作为引用传递的。但是当我删除b时,它仍然存在于c中。请看这个例子:

这第一部分对我来说很有意义,因为它是通过引用传递的:

var a = b: val:true;

a.c = a.b;
a.b.val = 'rawr';

console.log(uneval(a)); // outputs: "(b:val:"rawr", c:val:"rawr")"

现在这部分对我来说没有意义:

var a = b: val:true;

a.c = a.b;
a.b.val = 'rawr';
delete a.b;

console.log(uneval(a)); // outputs: "(c:val:"rawr")"

所以b 属性被删除,但c 属性将属性保存到删除之前引用的内容。这是javascript中的错误吗?

编辑: 感谢大家的回复!所以它不是错误,而且这种行为实际上非常好,它允许人们在保留对象的同时更改“键”/“属性”名称! :)

【问题讨论】:

谢谢阿瓦尔!我会重新命名它。 P.S.如果您使用调试器,最好只使用console.log(a) 而不是console.log(uneval(a)),因为它会向您显示属性和其他有用的调试内容(firebug 和 chrome 控制台)。 "我认为对象是作为引用传递的。" JavaScript 总是按值传递,就像 Java 一样。 谢谢大家。是的,关于console.log,你是对的,但我在 uneval 中做了只是为了在这个例子中显示输出。感谢您提供按值传递的说明。 【参考方案1】:

不,这不是 JavaScript 中的错误。

您对a.c = a.b 所做的是创建另一个指向同一个对象的链接,这意味着a.ba.c 都在引用同一个子对象val: "rawr"

当您执行delete a.b 时,您并没有删除子对象,您只是从a 中删除了a.b 属性。这意味着a.c 仍将引用同一个对象。

如果您也删除了a.c 属性,那么子对象将消失。

【讨论】:

感谢弗罗斯特的解释!我的下一个问题是如何删除该子对象,您也回答了这个问题,如果没有任何东西持有对该对象的引用(通过删除 a.c),那么它就完全消失了。非常感谢!这种行为实际上非常好,它允许人们在保留对象的同时更改“key”/“property”名称! :)【参考方案2】:

不,这不是错误。

delete 命令不会删除该属性所引用的对象,它只会删除该属性。如果该对象是从其他地方引用的(在这种情况下是另一个属性),则该对象仍然存在。

这就像你有两个变量指向同一个对象,并改变一个变量的值:

var a =  val: true ;
var b = a;
a = null;
console.log(b.val); // b still has a reference to the object

【讨论】:

感谢 Guffa 提供的替代示例来解释这一点,非常感谢!【参考方案3】:

那是因为:

delete 操作符从对象中删除一个属性。 MDN Delete

Object val: true 对应的条目 b 已从a 中删除。 a 中的条目 c 仍然引用此对象。如果您尝试删除c.vala.b.val,您仍然可以看到层叠到另一个的效果。

您正在尝试做的事情,即释放数据并期望它被级联,不会发生在 javascript 中。如果您有 C++ 背景,请考虑将所有 javascript 对象都视为引用计数。我可以删除对它的引用(即“指向”该对象的条目),但我不能删除对象本身。这是 javascript 引擎的纯粹特权。

【讨论】:

感谢 Sharadh,这是一个非常有趣的观点:如何从 a 中删除 val 属性在 b 中也是相同的。 当然,随时。这和你的例子一样。就像将 Object 中的键 val 的值更改为 rawr 一样,这里我们从对象本身中删除键。【参考方案4】:

通过这一行,你认为 c 指向 b:

a.c = a.b;

但实际上 c 和 b 都指向 val:true 对象,所以如果你删除 b,对象仍然存在。 您可以简单地认为 c 和 b 都只是“标签”贴在 val:true 对象上

【讨论】:

感谢耶利弗!您使用的不同词语确实强化了其他人所说的话。我非常感谢这些多重解决方案!【参考方案5】:

有两点需要注意,首先,正如其他答案中所说,delete关键字仅删除您访问该属性的对象的属性。

要注意的第二件事是 JavaScript 永远不会通过引用传递。它总是作为值传递,值有时是引用。

例如:

var a = 
   someObject: 
;
var someObject = a.someObject;

someObject = 'Test';

console.log(a.someObject); // outputs 

在通过引用传递的语言中,这可能会导致错误,因为它通常意味着强变量类型。

【讨论】:

感谢pass by value 的更正,这对我有很大帮助。这是你提出的一个很好的观点,我认为这是理所当然的,没有考虑它。非常感谢您的澄清。【参考方案6】:

...我迟到了?这是我对它的解释(也请阅读其他答案,这只是为了用视觉表示来支持这些答案):

    用另一个对象 (value:true) 初始化空对象 a

    为空对象 a 分配一个属性 b 引用另一个对象 (value:true)。

    为对象a分配属性c引用同一个对象 (value:true)。

    删除 b,因此a.b 不再子对象(value:true)。

    主要对象a的最终表示。

所以我们可以通过视觉表示很容易地看到子对象是如何被保存的:)

【讨论】:

这很棒。我喜欢视觉表现。 这真是太棒了感谢这个视觉解释!当我们删除 b 和 c 的两个 props 时,你能添加到视觉效果中吗?子对象不应该消失吗? @Noitidart 是的,它会消失。以后有时间再补充说明。 稍作修改后,我们就用小图片描述了整个垃圾收集过程! (只需在云上编写 GC-Magic 并让对象消失) 当我试图以图形方式说明 GC 时,我通常会使用一些有点像 pacman 的东西。

以上是关于即使在删除原始属性后,通过引用复制到第二个属性的对象仍然存在?的主要内容,如果未能解决你的问题,请参考以下文章

Kivy - 通过引用根属性动态添加按钮

角度材料:弹出窗口:允许窗口移动到第二个监视器屏幕

vuejs 复制数据对象和删除属性也会从原始对象中删除属性

深拷贝和浅拷贝

通过第一个表的元素访问第二个表的属性

加载第二个模型时,第一个模型的属性会被删除