Syn*_*cro 1 javascript oop object
假设我们有两个对象:
var a = { foo: { bar: 1 } }
var b = { foo: { bar: 2 } }
Run Code Online (Sandbox Code Playgroud)
如果我将对象 b 设置为 a ( a = b),我期望 a 采用 b 的值,而不是引用。所以,在这种情况下:
a = b
a.foo.bar = 3
console.log(b.foo.bar);
Run Code Online (Sandbox Code Playgroud)
我预计最后一个console.log显示的是 2,而不是 3。为什么?只是因为我更改了与 相关的属性a,而不是与b.
我不明白为什么 JavaScript 也会更改b属性以及如何避免这种意外行为。
如何避免这种行为?我应该以不同的方式将对象分配给变量吗?
\n\n...我希望 a 采用 b 的值,而不是引用...
\n
这是不正确的。变量包含值。对于对象,该值是一个“对象引用”,它告诉 JavaScript 引擎该对象在内存中的位置(其他位置)。\xc2\xb9 因此,a = b“a指向”同一个对象b“指向”。如果更改该对象的属性,无论您从哪个变量获取引用,您都会观察到这些更改。
初始设置后,内存中会有类似这样的内容(省略了各种细节):
\n\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\ x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+\na: Ref5465\xe2\x88\x92\xe2\ x88\x92\xe2\x88\x92\xe2\x88\x92>| (对象) |\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+ +\xe2\x88\x92\xe2 \x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88 \x92+\n | foo: Ref8761 |\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92>| (对象) |\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+ +\xe2\x88\x92\xe2 \x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88 \x92+\n | 栏: 1 |\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+\n\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88 \x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92 \xe2\x88\x92+\nb: Ref1574\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92>| (对象) |\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+ +\xe2\x88\x92\xe2 \x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88 \x92+\n | foo: Ref4456 |\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92>| (对象) |\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+ +\xe2\x88\x92\xe2 \x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88 \x92+\n | 栏: 2 |\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+\n\n
(当然,这些“ref”值是概念性的;我们从未真正看到它们。)
\n那么当你这样做时,用于引用的a = b对象就有资格进行垃圾回收,并且你会得到这个:a
\na: Ref1574\xe2\x88\x92\xe2\x88\x92+\n |\n |\n | +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+\n +\xe2\x88\x92>| (对象)|\n | +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+ +\xe2\x88\x92\xe2\x88\x92\xe2 \x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+\n | | foo: Ref4456 |\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92>| (对象)|\n | +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+ +\xe2\x88\x92\xe2\x88\x92\xe2 \x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+\nb: Ref1574 \xe2\x88\x92\xe2\x88\x92+ | 条: 2 |\n +\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\ xe2\x88\x92\xe2\x88\x92\xe2\x88\x92+\n\n
请注意a现在如何具有相同的“ref”值b。因此,很自然地,a.foo.bar = 3会更改和(间接)指向的一个bar属性。ab
如果要创建对象的副本a = Object.assign({}, b),可以使用或 (在 ES2018+ 中)进行浅复制a = {...b}。但如果你想复制foo引用的对象,你就需要深拷贝;查看这个问题的答案。
\xc2\xb9 有些人,特别是在学术背景下,会说对象本身就是价值,而“对象引用”是一个低级的管道概念,这是我们注意到对象之间差异的唯一原因,例如,数字表明对象是可变的。我理解他们的观点,但我采取务实的态度。
\n