即使在删除原始属性后,通过引用复制到第二个属性的对象仍然存在?
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.b
和a.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.val
或a.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 的东西。以上是关于即使在删除原始属性后,通过引用复制到第二个属性的对象仍然存在?的主要内容,如果未能解决你的问题,请参考以下文章