Как назначение переменной работает в JavaScript?

Таким образом, я играл на днях, чтобы посмотреть, как работает массовое задание в JavaScript.

Сначала я попробовал этот пример в консоли:

a = b = {};
a.foo = 'bar';
console.log(b.foo);

Результатом стал "бар", отображаемый в предупреждении. Это справедливо, a и b - это просто псевдонимы одного и того же объекта. Тогда я подумал: как я могу сделать этот пример более простым.

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

Это почти то же самое, не так ли? На этот раз он возвращает foo не bar как я ожидал бы от поведения первого примера.

Почему это происходит?

NB Этот пример может быть упрощен еще более с помощью следующего кода:

a = {};
b = a;
a.foo = 'bar';
console.log(b.foo);

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

Ответ 1

В первом примере вы устанавливаете свойство существующего объекта. Во втором примере вы назначаете совершенно новый объект.

a = b = {};

a и b теперь указывают на один и тот же объект. Поэтому, когда вы это делаете:

a.foo = 'bar';

Он также устанавливает b.foo так как a и b указывают на один и тот же объект.

Однако!

Если вы сделаете это вместо этого:

a = 'bar';

Вы говорите, что указывает на другой объект в настоящее время. a Это не имеет никакого влияния на то, что указал ранее. a

В JavaScript назначение переменной и присвоение свойства - это две разные операции. Лучше всего думать о переменных как о указателях на объекты, а когда вы назначаете непосредственно переменной, вы не изменяете какие-либо объекты, просто переставляя свою переменную на другой объект.

Но присваивание свойства, например a.foo, изменит объект, a указывает точка. Это, конечно же, также изменяет все другие ссылки, указывающие на этот объект, просто потому, что все они указывают на один и тот же объект.

Ответ 2

Ваш вопрос уже удовлетворительно ответил Squeegy - он не имеет ничего общего с объектами и примитивами, но с переназначением переменных и настроек свойств в том же ссылочном объекте.

В ответах и ​​комментариях есть много путаницы в отношении типов JavaScript, поэтому здесь представлено небольшое введение в систему типа JavaScript:

В JavaScript есть два принципиально разных вида значений: примитивы и объекты (и нет такой вещи, как хэш).

Строки, числа и булевы, а также null и undefined являются примитивами, объекты - все, что может иметь свойства. Даже массивы и функции являются регулярными объектами и поэтому могут содержать произвольные свойства. Они просто отличаются внутренним свойством [[Class]] (функции дополнительно имеют свойство, называемое [[Call]] и [[Construct]], но эй, эти детали).

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

Вот пример:

var a = 'quux';
a.foo = 'bar';
document.writeln(a.foo);

Это приведет к выходу undefined: a содержит примитивное значение, которое присваивается объекту при назначении свойства foo. Но этот новый объект немедленно отбрасывается, поэтому теряется значение foo.

Подумайте об этом так:

var a = 'quux';
new String(a).foo = 'bar'; // we never save this new object anywhere!
document.writeln(new String(a).foo); // a completly new object gets created

Ответ 3

Вы более или менее корректны, за исключением того, что то, что вы называете "хешем", на самом деле является просто сокращенным синтаксисом для объекта.

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

Ответ 4

вот моя версия ответа:

obj = {a:"hello",b:"goodbye"}
x = obj
x.a = "bonjour"

// now obj.a is equal to "bonjour"
// because x has the same reference in memory as obj
// but if I write:
x = {}
x.a = obj.a
x.b = obj.b
x.a = "bonjour"

// now x = {a:"bonjour", b:"goodbye"} and obj = {a:"hello", b:"goodbye"}
// because x points to another place in the memory

Ответ 5

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

Ответ 6

В первом случае вы изменяете какое-либо свойство объекта, содержащегося в переменной, во втором случае вы назначаете новое значение переменной. Это принципиально разные вещи. Переменные a и b не связаны каким-то магическим образом с помощью первого присваивания, они просто содержат один и тот же объект. Это также случай во втором примере, пока вы не назначите новое значение переменной b.

Ответ 7

Разница между простыми типами и объектами.

Все, что объект (например, массив или функция) передается по ссылке.

Все, что скопирован простой тип (например, строка или число).

У меня всегда есть функция copyArray, поэтому я могу быть уверен, что не создаю кучу псевдонимов в один и тот же массив.