Javascript указатель / ссылка сумасшествие. Может кто-нибудь объяснить это?


Javascript передает объекты по ссылке. В этом есть смысл. Но как только вы начинаете манипулировать этими объектами, все действует так, что кажется неинтуитивным. Позвольте мне привести пример:

var a, b;

a = {}
b = a;
a['one'] = {};

console.log( JSON.stringify(a) );
// outputs: {"one":{}}

console.log( JSON.stringify(b) );
// outputs: {"one":{}}

это все хорошо и хорошо, потому что сейчас b есть указатель на a так что ожидается, что назначение вещи a также повлияет b.

но тогда, если я делаю это:

a = a['one'];

console.log( JSON.stringify(a) );
// outputs: {}

console.log( JSON.stringify(b) );
// outputs: {"one":{}}

это удивительно для меня. Я бы ожидал a и b быть все тем же (и быть {} С a['one'] ранее было установлено значение {} и a был установлен до a['one']).

но это не так. Оказывается, что a теряет свою ссылку на b когда он назначен на что-то новое, но b сохраняет значение a был установлен до a потеря ссылки на b.

но тогда, если я делаю это:

a['two'] = 2;

console.log( JSON.stringify(a) );
// outputs: {"two":2}

console.log( JSON.stringify(b) );
// outputs: {"one":{"two":2}}

что? a явно потерял его ссылка на b, а b кажется, все еще есть некоторые ссылки на a.

делает пустой объект {} укажите на какое-то место в памяти, чтобы каждая переменная, ссылающаяся на нее, теперь указывала на одно и то же место?

может кто-то с твердым пониманием этого объяснить мне это?

5 58

5 ответов:

пример строки:

a = {}

a теперь ссылается на новый объект.

b = a;

b теперь ссылается на тот же объект, что a ссылки. Обратите внимание, что он не ссылается a.

a['one'] = {};

новый объект теперь имеет индекс 'one', который ссылается на другой новый объект.

когда вы

a = a['one'];

вы a относятся к a['one'], которая заключается в том, что новый объект создан, когда вы сделали a['one'] = {}. b по-прежнему ссылается на объект, созданный с помощью a = {}.

Вы путаете вопрос, когда вы говорите:"a потерял ссылку на b", поскольку a не относится к b , и наоборот. a и b смотрите объекты, и их можно заставить ссылаться на другие объекты. Вот так:

С a = {}; b = a вы получаете

a
 \
  \
   { }
  /
 /
b

затем с a['one'] = {} вы получить

a
 \
  \
   { one: { } }
  /
 /
b

затем с a = a['one'] вы получаете

a - - - - 
          \
   { one: { } }
  /
 /
b

:P вы спускаетесь в вязаные песчаные детали, и я рад, что вы спросили, как вы будете мудрее к концу.

не смотрите на это с точки зрения указателей, потому что я думаю, что это то, где вы путаетесь. Подумайте об этом скорее с точки зрения кучи (или просто "памяти", если хотите) и таблицы символов.

давайте начнем с первых строк вашего кода:

var a, b;

a = {}
b = a;

то, что вы сделали здесь, создается один объект в куче и два символы в таблице символов. Это выглядит примерно так:


Таблица Символов:

+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
|      a |        0x400000 |
+--------+-----------------+
|      b |        0x400000 |
+--------+-----------------+

кучу:

+----------+-----------------+
| Location | Value           |
+----------+-----------------+
| 0x400000 | <object val 1>  |
+----------+-----------------+

.


вот где все становится интересным: объекты имеют свои собственные "таблицы символов" (обычно это просто хэш-таблицы, но называя его таблицей символов, можно сделать ее более ясной).

теперь, после вашего очередного заявления, у вас есть 3 вещи, чтобы рассмотреть: глобальный символ стол,<object val 1>таблица символов и куча.

выполнить следующую строку:

a['one'] = {}

и теперь все выглядит так:


Глобальная Таблица Символов:

+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
|      a |        0x400000 |
+--------+-----------------+
|      b |        0x400000 |
+--------+-----------------+

<object val 1> таблица символов

+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
|    one |        0x400004 |
+--------+-----------------+

кучу:

+----------+-----------------+
| Location | Value           |
+----------+-----------------+
| 0x400000 | <object val 1>  |
+----------+-----------------+
| 0x400004 | <object val 2>  |     <---we created a new object on the heap
+----------+-----------------+

.


теперь вы запустили следующий код:

a = a['one'];

это должно, надеюсь, показаться тривиальное изменение. В результате получается:


Глобальная Таблица Символов:

+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
|      a |        0x400004 |
+--------+-----------------+
|      b |        0x400000 |
+--------+-----------------+

<object val 1> таблица символов

+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
|    one |        0x400004 |
+--------+-----------------+

кучу:

+----------+-----------------+
| Location | Value           |
+----------+-----------------+
| 0x400000 | <object val 1>  |
+----------+-----------------+
| 0x400004 | <object val 2>  | 
+----------+-----------------+

.


после расположения памяти в куче, мы надеемся, прояснить, почему вы получили результат, который вы сделали.

теперь все становится еще интереснее, потому что теперь вы делать:

a['two'] = 2;

ок, Так давайте сделаем это шаг за шагом.

  • a указывает на место памяти 0x400004, которая содержит <object val 2>
  • <object val 2> является пустым объектом, поэтому его таблица символов начинается с пустого
  • запустив эту строку, мы добавим переменную ' two ' в <object val 2>таблица обозначением s.

если вы еще не устали смотреть на эти диаграммы, вы будете. Теперь все выглядит так это:


Глобальная Таблица Символов:

+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
|      a |        0x400004 |
+--------+-----------------+
|      b |        0x400000 |
+--------+-----------------+

<object val 1> таблица символов

+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
|    one |        0x400004 |
+--------+-----------------+

<object val 2> таблица символов

+--------+-----------------+
| Symbol | Memory Location |
+--------+-----------------+
|    two |        0x400008 |
+--------+-----------------+

кучу:

+----------+-----------------+
| Location | Value           |
+----------+-----------------+
| 0x400000 | <object val 1>  |
+----------+-----------------+
| 0x400004 | <object val 2>  | 
+----------+-----------------+
| 0x400008 | 2 (literal val) |    <-- yes, even integers are stored on the heap
+----------+-----------------+        in JavaScript.

.


если вы старательно потратите время, чтобы следить за местами памяти, вы увидите, что ваш браузер отобразил правильный вывод.

подумайте об анонимном объекте как о самом себе, имеющем имя:

a = {}; // The variable "a" now points to (holds) an anonymous object.
b = a; // "b" points to the same anonymous object held by "a".
a = 123; // "a" now holds some other value.
b; // "b" still holds the anonymous object.

ключ должен помнить, что переменные хранят ссылки на объекты, а не ссылки на другие переменные. И на один и тот же объект может ссылаться любое количество переменных.

объекты в Javascript могут существовать сами по себе, не нуждаясь в имени. Например:

{}

новый экземпляр объекта словаря.

a = {};

создает новый объект словаря и делает a обратитесь к нему. Сейчас

b = a;

делает b обратитесь к тому же базовому объекту. Затем вы можете сделать a укажите куда-нибудь еще:

a = "hi";

и b по-прежнему указывает на тот же объект словаря и раньше. Этот поведение b не имеет отношения к тому, как вы изменить то, что a указывает.

насколько я знаю, вы overwrited a поэтому я думаю, что двигатель сохраняет его в другом пространстве памяти, тогда как b все еще указывая на старый a адрес памяти (который почему-то не уничтожается).