JavaScript对象分配:意外行为

时间:2018-10-05 10:06:39

标签: javascript oop object

假设我们有两个对象:

var a = { foo: { bar: 1 } }
var b = { foo: { bar: 2 } }

如果将对象b设置为a(a = b),则我希望a取b的值,而不是引用的值。因此,在这种情况下:

a = b
a.foo.bar = 3
console.log(b.foo.bar);

我希望最后一个console.log显示2,而不是3。为什么?只是因为我更改了与a而不是b相关的属性。

我不明白为什么JavaScript还会更改b属性以及如何避免这种意外行为。

如何避免这种行为?是否应该以其他方式将对象分配给变量?

1 个答案:

答案 0 :(得分:3)

  

...我希望a取b的值,而不是引用的值...

那是不对的。变量包含值。对于对象,该值是“对象引用”,它告诉JavaScript引擎该对象在内存中的其他位置。因此a = b使a“指向”同一对象b“指向”。如果更改该对象的属性,则无论您从中获取引用的变量如何,都将观察到这些更改。

初始设置后,您的内存中会出现以下内容(省略了许多详细信息):

               +−−−−−−−−−−−−−−+
a: Ref5465−−−−>|   (object)   |
               +−−−−−−−−−−−−−−+     +−−−−−−−−−−+
               | foo: Ref8761 |−−−−>| (object) |
               +−−−−−−−−−−−−−−+     +−−−−−−−−−−+
                                    | bar: 1   |
                                    +−−−−−−−−−−+

               +−−−−−−−−−−−−−−+
b: Ref1574−−−−>|   (object)   |
               +−−−−−−−−−−−−−−+     +−−−−−−−−−−+
               | foo: Ref4456 |−−−−>| (object) |
               +−−−−−−−−−−−−−−+     +−−−−−−−−−−+
                                    | bar: 2   |
                                    +−−−−−−−−−−+

(这些“ ref”值当然是概念性的;我们从未真正看到它们。)

然后,当您执行a = b时,a曾经引用的对象才有资格进行垃圾回收,而您可以使用它:

a: Ref1574−−+
            |
            |
            |  +−−−−−−−−−−−−−−+
            +−>|   (object)   |
            |  +−−−−−−−−−−−−−−+     +−−−−−−−−−−+
            |  | foo: Ref4456 |−−−−>| (object) |
            |  +−−−−−−−−−−−−−−+     +−−−−−−−−−−+
b: Ref1574−−+                       | bar: 2   |
                                    +−−−−−−−−−−+

请注意,a现在如何具有相同的“ ref”值b。自然,a.foo.bar = 3更改了bara(间接)指向的一个b属性。

如果要对对象进行复制,则可以使用a = Object.assign({}, b)或(在ES2018 +中)a = {...b}进行浅表复制。但是,如果要复制对象foo所指的对象,则需要 deep 复制。参见this question's answers