← all writing

Primitive and Reference Types In JavaScript

Primitive Types

JavaScript has 5 data types that are copied by value: Boolean, null, undefined, String and Number. We will call these primitive types. This is also called pass-by-value.

const x = 10;
const y = 'abc';
VariableValue
x10
yabc

When we assign these variables to other variables using =, we create a copy of the value and store it in the new variable. This process is known as copying by value.

const x = 10;
const y = 'abc';
const z = x;

both x and z are separate as the values themselves were copied.

VariableValue
x10
yabc
z10

Reference Types

Objects and Arrays are known as reference types. This means that when you assign an object or an array to a new variable, you don't actually create a full copy of the data. Instead, the new variable holds a reference or a pointer to the original data stored in memory. This behavior is referred to as "pass-by-reference."

const array1 = [1, 2, 3];
const array2 = array1;
 
array2.push(4);
console.log(array2);               // [1, 2, 3, 4]
console.log(array1);               // [1, 2, 3, 4]

Both array2 and array1 refer to the same object in memory. As a result, if we make changes to one of them, both arrays will be affected.

VariableAddress
array1<#001>
array2<#001>
AddressValue
<#001>[1, 2, 3, 4]

The solution is to manually clone the array.

const array1 = [1, 2, 3];
const array2 = [...array1];
 
array2.push(4);
console.log(array2);          // [1, 2, 3, 4]
console.log(array1);          // [1, 2, 3]
VariableAddress
array1<#001>
array2<#002>
AddressValue
<#001>[1, 2, 3]
<#002>[1, 2, 3, 4]

In case of object:

const referenceObj = {
  name: 'Deepak',
  hobbies: ['coding', 'learning']
};
 
const newObj = referenceObj;
newObj.job = 'Front-End Engineer';
 
console.log(newObj.job);                      // Front-End Engineer
console.log(referenceObj.job);                // Front-End Engineer
VariableAddress
referenceObj<#001>
newObj<#001>
AddressValue
<#001>{ name: 'Deepak', hobbies: ['coding', 'learning'] }

The solution is to manually clone the object:

const referenceObj = {
  name: 'Deepak',
  hobbies: ['coding', 'learning']
};
 
const newObj = { ...referenceObj };
 
newObj.hobbies.push('walking');               // this still edits the original hobbies array
 
console.log(referenceObj.hobbies);            // ['coding', 'learning', 'walking']
console.log(newObj.hobbies);                  // ['coding', 'learning', 'walking']

This is called shallow cloning, which only creates copies one level deep.

The solution is to manually clone the array also.

const referenceObj = {
  name: 'Deepak',
  hobbies: ['coding', 'learning']
};
 
const newObj = {
  ...referenceObj,
  hobbies: [...referenceObj.hobbies]
};
 
newObj.hobbies.push('walking');

This is called deep cloning.

VariableAddress
referenceObj<#001>
newObj<#002>
AddressValue
<#001>{ name: 'Deepak', hobbies: ['coding', 'learning'] }
<#002>{ name: 'Deepak', hobbies: ['coding', 'learning', 'walking'] }

Comparison

If the variables contain a reference to the same item, the comparison will result in true.

const array1 = [1, 2, 3];
const array2 = array1;
console.log(array1 === array2);   // true

If they're distinct objects, even if they contain identical items, the comparison will result in false.

const arr = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr === arr2);        // false

Reassign

let obj = { name: 'Deepak' };
obj = { name: 'Piyush' };

The first one is garbage collected.

Questions

1. What will be the output of the following program?

const array1 = [1, 2, 3];
const array2 = array1;
console.log(array1 === array2);

Answer — true

VariableValue
array1<001>
array2<001>

2. What will be the output of the following program?

const array1 = [1, 2, 3];
const array2 = [1, 2, 3];
console.log(array1 === array2);

Answer — false

VariableValue
array1<001>
array2<002>

3. What will be the output of the following program?

function changeAgeAndReference(person) {
  person.age = 25;
  person = {
    name: 'John',
    age: 50
  };
  return person;
}
 
const personObj1 = {
  name: 'Alex',
  age: 30
};
 
const personObj2 = changeAgeAndReference(personObj1);
 
console.log(personObj1); // -> ?
console.log(personObj2); // -> ?

Answer:

{ name: 'Alex', age: 25 }
{ name: 'John', age: 50 }

Explanation: The function first changes the property age on the original object it was passed in. It then reassigns the variable to a brand new object and returns that object. Here's what the two objects are logged out:

console.log(personObj1); // -> { name: 'Alex', age: 25 }
console.log(personObj2); // -> { name: 'John', age: 50 }

Remember that assignment through function parameters is essentially the same as an assignment with =. The variable person in the function contains a reference to the personObj1 object, so it initially acts directly on that object. Once we reassign person to a new object, it stops affecting the original.

This reassignment does not change the object that personObj1 points to in the outer scope. person has a new reference because it was reassigned but this reassignment doesn't change personObj1.

4. What will be the output of the following program?

const personObj1 = {
  name: 'Christa',
  age: 20
};
 
let person = personObj1;
person.age = 25;
 
person = {
  name: 'John',
  age: 50
};
 
const personObj2 = person;
 
console.log(personObj1);
console.log(personObj2);

Answer:

{ name: 'Christa', age: 25 }
{ name: 'John', age: 50 }

5. What will be the output of the following program?

const obj = {
  innerObj: {
    x: 9
  }
};
 
const z = obj.innerObj;
 
z.x = 25;
 
console.log(obj.innerObj.x);

Answer — 25

6. What will be the output of the following program?

const obj = {
  arr: [{ x: 17 }]
};
 
let z = obj.arr;
 
z = [{ x: 25 }];
 
console.log(obj.arr[0].x);

Answer — 17

7. What will be the output of the following program?

const obj = {
  arr: []
};
 
obj.arr.push(17);
 
console.log(obj.arr === [17]);

Answer — false

8. Write a simple program to demonstrate pass-by-value for primitive types in JavaScript.

function modifyValue(x) {
  x = x + 10;
  console.log("Inside function:", x);
}
 
let num = 5;
console.log("Before function:", num);
modifyValue(num);
console.log("After function:", num);

Answer:

Before function: 5
Inside function: 15
After function: 5

9. Write a program to show how objects behave with pass-by-reference in JavaScript.

function modifyProperty(obj) {
  obj.name = "John";
}
 
const person = {
  name: "Alice",
  age: 30
};
 
console.log("Before function:", person);
modifyProperty(person);
console.log("After function:", person);

Answer:

Before function: { name: "Alice", age: 30 }
After function: { name: "John", age: 30 }