102

So I was playing around the other day just to see exactly how mass assignment works in JavaScript.

First I tried this example in the console:

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

The result was "bar" being displayed in an alert. That is fair enough, a and b are really just aliases to the same object. Then I thought, how could I make this example simpler.

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

That is pretty much the same thing, isn't it? Well this time, it returns foo not bar as I would expect from the behaviour of the first example.

Why does this happen?

N.B. This example could be simplified even more with the following code:

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

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

(I suspect that JavaScript treats primitives such as strings and integers differently to hashes. Hashes return a pointer while "core" primitives return a copy of themselves)

jak.b
  • 273
  • 4
  • 15
Chris Lloyd
  • 12,100
  • 7
  • 36
  • 32
  • Explaining assignment here: http://www.syntaxsuccess.com/viewarticle/javascript-variable-assignment-explained – TGH Oct 25 '17 at 03:25

7 Answers7

118

In the first example, you are setting a property of an existing object. In the second example, you are assigning a brand new object.

a = b = {};

a and b are now pointers to the same object. So when you do:

a.foo = 'bar';

It sets b.foo as well since a and b point to the same object.

However!

If you do this instead:

a = 'bar';

you are saying that a points to a different object now. This has no effect on what a pointed to before.

In JavaScript, assigning a variable and assigning a property are 2 different operations. It's best to think of variables as pointers to objects, and when you assign directly to a variable, you are not modifying any objects, merely repointing your variable to a different object.

But assigning a property, like a.foo, will modify the object that a points to. This, of course, also modifies all other references that point to this object simply because they all point to the same object.

Volker E.
  • 5,911
  • 11
  • 47
  • 64
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • 3
    "you are saying that a points to a different object now." No, don't use the word object. A string is not an object in JavaScript. – Nosredna Feb 04 '09 at 00:41
  • 1
    Ah that makes so much more sense to me now! Thank you! (And now it makes sense I feel like an idiot...) – Chris Lloyd Feb 04 '09 at 00:48
  • 11
    Maybe strings aren't technically of the javascript type "Object", but they can be thought of objects in the OO sense. – Alex Wayne Feb 04 '09 at 01:13
  • 2
    @Squeegy: strings are primitives, not objects: you can't assign arbitrary properties to strings! They only behave object-like because of what is called autoboxing in Java – Christoph Feb 04 '09 at 01:20
  • 11
    But strings have methods and properties, and String's prototype can definitely be modified. They sure act like objects. – Cameron Martin Feb 22 '12 at 23:32
  • 9
    @ddlshack: As Christoph explained, this is due to autoboxing. If you were to define a string via `var foo = new String('foo');`, then _that_ would be a string object (and `typeof` will confirm this). But if you declare it via a string literal, then they are string primitives. See: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/#Distinction_between_string_primitives_and_String_objects – Lèse majesté Jul 11 '12 at 22:56
  • No. The Difference is not because of "variable vs property". Here is the same thing happening for a property `a = {}; b = {}; a.foo = {name:'ozgur'}; b.foo = a.foo; // b.foo becomes an alias to a.foo console.log(b.foo.name); //prints ozgur, still inner object's reference is assigned` Behavior difference is because of "object vs primitive" – Ozgur Ozturk Jan 15 '15 at 04:57
  • @Lèsemajesté: It’s a prototype lookup. Nothing to do with autoboxing (a concept that doesn’t really exist in JavaScript except in regards to the `this` value, and even that doesn’t exist in strict mode). – Ry- Jan 08 '18 at 10:12
  • @OzgurOzturk: You missed the point of the distinction, and the correct one definitely isn’t “object vs. primitive”. – Ry- Jan 08 '18 at 10:15
28

Your question has already been satisfyingly answered by Squeegy - it has nothing to do with objects vs. primitives, but with reassignment of variables vs. setting properties in the same referenced object.

There seems to be a lot of confusion about JavaScript types in the answers and comments, so here's a small introduction to JavaScript's type system:

In JavaScript, there are two fundamentally different kinds of values: primitives and objects (and there is no thing like a 'hash').

Strings, numbers and booleans as well as null and undefined are primitives, objects are everything which can have properties. Even arrays and functions are regular objects and therefore can hold arbitrary properties. They just differ in the internal [[Class]] property (functions additionally have a property called [[Call]] and [[Construct]], but hey, that's details).

The reason that primitive values may behave like objects is because of autoboxing, but the primitives themselves can't hold any properties.

Here is an example:

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

This will output undefined: a holds a primitive value, which gets promoted to an object when assigning the property foo. But this new object is immediately discarded, so the value of foo is lost.

Think of it like this:

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
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • The Mozilla Foundation's page 'A re-introduction to JavaScript (JS tutorial)' describes JavaScript objects "as simple collections of name-value pairs. As such, they are similar to...", then follows with a list of dictionaries, hash, hash tables, and hash maps from various programming languages. The same page describes object property references as hash table lookups. So objects are everything like a 'hash' table. This does not nullify the other useful information, but Chris Lloyd's original characterization was not inaccurate. – C Perkins Dec 23 '16 at 04:55
3

You're more or less correct except that what you're referring to as a "hash" is actually just shorthand syntax for an Object.

In the first example, a and b both refer to the same object. In the second example, you change a to refer to something else.

Kevin
  • 30,111
  • 9
  • 76
  • 83
  • So why the double standards for Object? – Chris Lloyd Feb 04 '09 at 00:26
  • Its not a double standard. In the first example, a and b still refer to the same object, you're just modifying a property of that object. In the second example, you're pointing a at a different object. – Kevin Feb 04 '09 at 00:27
  • 1
    No, the difference is that in the second case, you're dealing with a string, not an object. – Nosredna Feb 04 '09 at 00:32
  • 1
    To be clear: This has nothing to do with strings returning a copy of themselves. The reason the two code snippets are different is in Kevin's second paragraph (explained more fully in Squeegy's answer). – Chuck Feb 04 '09 at 00:35
  • It doesn't matter if you have a string or an object in the variable. You assign a new, different value and then the variable contains that new, different value. – sth Feb 04 '09 at 00:39
  • The first statement can be turned around to say a JavaScript "object" is just shorthand for a hash table of property names. Chris Lloyd's characterization of objects as hashes is completely legit. Mozilla Foundation's page 'A re-introduction to JavaScript (JS tutorial)' describes objects as a simple hash table similar to related constructs in various other programming languages. – C Perkins Dec 23 '16 at 05:05
2

here is my version of the answer:

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
AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
0

You are setting a to point to a new string object, while b keeps pointing to the old string object.

mdm
  • 5,528
  • 5
  • 29
  • 28
0

In the first case you change some property of the object contained in the variable, in the second case you assign a new value to the variable. That are fundamentally different things. The variables a and b are not somehow magically linked by the first assignment, they just contain the same object. That's also the case in the second example, until you assign a new value to the b variable.

sth
  • 222,467
  • 53
  • 283
  • 367
0

The difference is between simple types and objects.

Anything that's an object (like an array or a function) is passed by reference.

Anything that's a simple type (like a string or a number) is copied.

I always have a copyArray function handy so I can be sure I'm not creating a bunch of aliases to the same array.

Nosredna
  • 83,000
  • 15
  • 95
  • 122
  • The difference is not noticeable in many scenarios, but Javascript doesn't actually pass or assign by reference. It copies reference values. – Juan Pablo Califano Feb 04 '09 at 00:54
  • These guys have already made a good work explaining it, so I'll just paste the link: http://stackoverflow.com/questions/40480/is-java-pass-by-reference (I refers to Java, but the semantics for passing and assigning values / references are the same as in Javascript) – Juan Pablo Califano Feb 04 '09 at 01:05
  • 1
    Actually this answer is incorrect, everything is passed by value in JavaScript. From MDN, "The parameters of a function call are the function's arguments. Arguments are passed to functions by value. If the function changes the value of an argument, this change is not reflected globally or in the calling function. However, object references are values, too, and they are special: if the function changes the referred object's properties, that change is visible outside the function." https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope – bittersweetryan Jun 25 '13 at 20:09
  • Primitives behave like immutable objects (*exactly* like them in strict mode). This answer is not correct. – Ry- Jan 08 '18 at 10:10