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';| Variable | Value |
|---|---|
| x | 10 |
| y | abc |
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.
| Variable | Value |
|---|---|
| x | 10 |
| y | abc |
| z | 10 |
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.
| Variable | Address |
|---|---|
| array1 | <#001> |
| array2 | <#001> |
| Address | Value |
|---|---|
<#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]| Variable | Address |
|---|---|
| array1 | <#001> |
| array2 | <#002> |
| Address | Value |
|---|---|
<#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| Variable | Address |
|---|---|
| referenceObj | <#001> |
| newObj | <#001> |
| Address | Value |
|---|---|
<#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.
| Variable | Address |
|---|---|
| referenceObj | <#001> |
| newObj | <#002> |
| Address | Value |
|---|---|
<#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); // trueIf 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); // falseReassign
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
| Variable | Value |
|---|---|
| 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
| Variable | Value |
|---|---|
| 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 }