Назначение объекта JavaScript: неожиданное поведение - PullRequest
0 голосов
/ 05 октября 2018

Предположим, у нас есть два объекта:

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 голосов
/ 05 октября 2018

... Я ожидаю, что 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 изменяет это свойство bar, на которое указывают a и b (косвенно).

Если вы хотите сделать копию объекта,Вы можете сделать поверхностную копию с помощью a = Object.assign({}, b) или (в ES2018 +) a = {...b}.Но если вы хотите скопировать объект, на который ссылается foo, вам потребуется копия deep ;см. ответы на этот вопрос .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...