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 ответов:
пример строки:
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
указывает.