1

So, I understand that arrays in JavaScript are mutable.

Meaning that if I create array a, and array b = a, then if I modify array a, the modification is also visible in array b.

However, in the following scenario I don't understand why b loses the "reference" to array a.

var a = [1,2,3];
var b = a;

console.log('a =', a);
console.log('b =', b);

a[0] = 4;
console.log('a =', a);
console.log('b =', b);

a = [5,5];
console.log('a =', a);
console.log('b =', b);
benvc
  • 14,448
  • 4
  • 33
  • 54
DonJoe
  • 1,603
  • 1
  • 13
  • 24
  • What Tyler said, and console logging will show elements as they are, not as they were so in the future when you log maybe do a `console.log(JSON.stringify(something,null,2))` instead. When you run this `var arr = [{name:'original'}]; console.log(arr); arr[0].name='changed'` then expand the console output it'll say "changed" but you logged it before you changed it. – HMR Jun 14 '19 at 18:52

3 Answers3

6

a and b are not references to eachother - they are references to the same array.

When you do a = [5,5], you set a to a totally new array, while b still refers to the old one.

Tyler Roper
  • 21,445
  • 6
  • 33
  • 56
  • And how would I tell `b` to keep a reference to whatever `a` contains? – DonJoe Jun 14 '19 at 18:53
  • 1
    @DonJoe Be more specific then, about how you want `[5, 5]` to affect the results in `a` and `b` – Taplar Jun 14 '19 at 18:54
  • 3
    @DoJoe JavaScript doesn't have the ability for variables to hold pointers so you don't but you could try setting a to b and have b be `{value:[1,2,3]}` then you can set b.value to whatever and a.value will change. – HMR Jun 14 '19 at 18:54
  • @DonJoe As Taplar points out, you'd need to elaborate a bit. There isn't really an inherent way to have one variable maintain the value of another, though there are some workarounds like HMR mentions. – Tyler Roper Jun 14 '19 at 18:56
  • https://medium.com/@naveenkarippai/learning-how-references-work-in-javascript-a066a4e15600 is a pretty good rundown of how references work in JS – Cal Irvine Jun 14 '19 at 18:56
  • @DonJoe JavaScript does not have pointers. [More information](https://stackoverflow.com/questions/17382427/are-there-pointers-in-javascript). Technically you could do something like [`Object.defineProperty('window', 'b', get() => this.a);`](https://jsfiddle.net/sc4adokn/), but this is ugly as it requires globals and whatnot. – Tyler Roper Jun 14 '19 at 18:58
  • @tylerRoper or `with({ a, get b() { return this.a; } }) { ... }` ;) – Jonas Wilms Jun 14 '19 at 19:03
  • 1
    @donJoe you can't have references to references in JS (in C you can point to a pointer). Variables can only reference values, there is no way for a variable to reference a variable. – Jonas Wilms Jun 14 '19 at 19:04
  • @DonJoe instead of a "pointer" use a function in JS. `var b = () => a;` *var b* now contains a function that will always return the current value stored in the variable `a`. And in JS you can pass this function around like every other value. That's the JS way to go. Maybe you want to read up about *closures*, *callbacks* and *functions as first class citizens*. – Thomas Jun 14 '19 at 23:21
3

Let's look into the computers memory¹. First of all, two variables get created, a and b. These are basically memory locations, that get filled with a value:

 location | name²      |  value
 -------------------------------------
  1       |  a         |  undefined
  2       |  b         |  undefined

Now a gets initialized, and a new array gets created. That array however doesn't get stored under the variable directly, but at another location, inside a there is just a reference to that location:

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 3
  2        |  b         |  undefined
  3        |            |  [1, 2, 3]

Now when you do b = a the reference gets copied, you end up at:

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 3
  2        |  b         |  ➡️ 3
  3        |            |  [1, 2, 3]

Now when you do a = [5,5] another array gets created, and a references that. b wasn't changed though, it still references the other array.

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 4
  2        |  b         |  ➡️ 3
  3        |            |  [1, 2, 3]
  4        |            |  [5, 5]

Or if you do b = {value: a} :

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 4
  2        |  b         |  ➡️ 5
  3        |            |  [1, 2, 3] // waiting for GC
  4        |            |  [5, 5]
  5        |            | { value: ➡️4 }

¹ yes, JavaScript is an interpreted language, so you won't know for sure how it ends up in the memory in the end, thats up to the engine. However, JS derives its concepts from other languages, and thats why it is often helpful to think on a low level.

² there is no such thing as a name of a specific memory location, I just added that for clarity.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
3

It may be helpful to think about "variables" as distinct from "values".

a and b in your example are variables.

[1,2,3], 4, and [5,5] in your example are values.

Multiple variables can reference the same value. If that value changes (mutates), then any and all variables that reference that value will return the altered value. Example below sets the references of both a and b to the same value, then makes changes to that value via both the reference from a and the reference from b. Result is that the changed value is still referenced by both variables.

var a = [1, 2, 3]; // a references the value [1,2,3]
var b = a; // b references the value [1,2,3]
a[0] = 4; // [1,2,3] changed to [4,2,3]
b[1] = 5; // [1,2,3] changed to [4,5,3]
console.log(a); // [4,5,3]
console.log(b); // [4,5,3]

However, you can change the value that a variable references altogether by "assigning" it to a new value. This will not change (mutate) the value itself nor will it change the reference of any other variable that happened to reference the same value. Example below sets the references of both a and b to the same value, then changes the reference of a to a new value. Result is that the variables now reference different values.

var a = [1, 2, 3]; // a references the value [1,2,3]
var b = a; // b references the value [1,2,3]
a = [5, 5]; // a reference assigned to new value [5,5]
console.log(a); // [5,5]
console.log(b); // [1,2,3]
benvc
  • 14,448
  • 4
  • 33
  • 54