e v m

Pass by value vs Pass by Reference

August 08, 2020
No comments

Everything in Javascript is an object except the primitive values. Primitive values are passed by copy and objects by reference.

Primitive Types:

  • String
  • Number
  • BigInt
  • Boolean
  • Symbol

The primitives above have object equivelants that wrap around the value and those objects have valueOf() method that returns the value.

  • undefined
  • null

null and undefined primitive values do not have object equivelants, but null is a typeof Object as a bug. For backwards compatibility it has remained as an object.

These types are the building blocks of the language, so they are very easy store and are stored directly by their value. Think of them as post it notes, you can write any information on them quickly, they are quickly accessible and when you are done, you can discard them.

Pass by value (Primitive Types)

1
let name = "Liam";
2
let name2 = "Liam";

Primitive values are cheap and easy to deal with, whenever you assign a primitive value to a variable, javascript engine knows exactly how much memory is needed and allocates the needed amount.

In this way, when name changes, name2 remains the same. They refer to different places in memory.

1
// afer you reassign name, its old value is garbage collected
2
name = "Emil";
3
name // Emil
4
name2 // Liam
5
6
function nameChanger (name2){
7
name2 = "Matilda";
8
return name2;
9
}
10
11
name2 // Liam
12
nameChanger(name2) // Matilda
13
name2 // Liam

The nameChanger function takes in a copy of the name2 variable, Liam, and then inside in its own scope, it has its own name variable that has the value of Liam. Let us see step by step

1
nameChanger("Liam")
2
// step by step what is happening
3
function nameChanger (name2){
4
// name === "Liam"
5
name2 = "Matilda"; // "Liam" value garbage collected,
6
// name2 in this scope is "Matilda"
7
return name2;
8
}

Objects (Functions, Arrays, Objects)

Objects on the other hand act differently as they are treated differently by the engine. Object, Arrays, Functions are complex structures. You can edit them, expand them, delete properties on them.

1
let user = {
2
name: "Emil",
3
age:23,
4
admin: false
5
}
6
7
user.name = "Liam"
8
9
console.log(user)
10
{
11
name: "Liam",
12
age:23,
13
admin: false
14
}

A new object is not created but the object is modified.

Pass by reference

When dealing with complex data, instead of copying the whole data (data objects could be gigabytes), language engines usually pass a reference to the memory address of the object.

Think of primitive values being a name on a post-it, and objects being a house. You do not want to move and copy the house each time someone asks, you want to give them the address. Javascript engines passes the reference to the object, it writes the address on a post-it, instead of creating the whole building again.

1
const mate0 = {
2
name: "Liam",
3
age: 20,
4
occupation: "student"
5
}
6
const mate1 = {
7
name: "Emil",
8
age: 25,
9
occupation: "Developer"
10
}
11
const house = {
12
price: 1_000_000,
13
bedrooms: 3,
14
sqm: 140,
15
housemates:[]
16
}
17
function addToHouse(array, house){
18
house.housemates = house.housemates.concat(array)
19
}
20
21
addToHouse([mate0, mate1], house)
22
console.log(house);
23
mate1.occupation = "bartender";
24
console.log(mate1)
25
//{name: "Liam", age: 20, occupation: "bartender"}
26
27
28
console.log("after change: ", house)
29
// {price: 1000000, bedrooms: 3, sqm: 140, housemates: Array(2)}
30
// housemates: Array(2)
31
// 0: {name: "Liam", age: 20, occupation: "bartender"}
32
// 1: {name: "Emil", age: 25, occupation: "Developer"}
33
34
house.housemates[1].name = 'Jack';
35
console.log(mate1) // Jack

After we run the addToHouse, with our house object and array of housemates, we mutated (programming term for change) the actual house object and added the housemates.

Afterwards when we mutated mate0’s occupation, the change was also reflected and when we mutated housemates[1].name through the house object, we changed mate2’s name to Jack.

So the objects in global scope and inside house.housemates array, both refer to the same memory locations. You can change them from both references. This might not always be desired, so you need to be careful.

That is why libraries like loadash have utilitiy functions for deep copying.

If we use object assign to copy the house object, it will create a shallow copy and we will still not have the desirable effect.


Written by Emil Martinov who lives Rotterdam || Istanbul and loves everything js. He tweets mostly about js.