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указывает.