This is going to be a long post but trust me it’s worth a read.
JavaScript is dynamically typed language which means types are not defined at compile time like other object-oriented languages. JavaScript provides two categories under which the data types are divided.
- Primitive Values
- Reference Values
Primitive Values:
In JavaScript, a primitive is data that is not an object and has no methods. There are 7 primitive data types: string, number, boolean, null, undefined, symbol, biginit.
Most of the time, a primitive value is represented directly at the lowest level of the language implementation.
All primitives are immutable, i.e., they cannot be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned a new value, but the existing value cannot be changed in the ways that objects, arrays, and functions can be altered.” - Source - MDN
To break the above definition, it simply means that in case of primitive values, it creates and assigns a fixed location in memory for the defined variable. The primitive values are stored on Stack and the name itself is intuitive enough to understand that it is a stack of data, which has LIFO i.e. last in first operation.
// Primitive Values..
let testString = 'Hello World';
let testString1 = testString;
console.log('testString:', testString); // Hello World
console.log('testNumber:', testString1 ); // Hello World
testString1 = 123;
console.log('testString:', testString); // Hello World
console.log('testNumber:', testString1 ); // 123
As we can see in the above code snippet, it copies and pastes and assigns a new location on stack.
Reference Values:
Reference values are objects stored in heap.Heapis a different kind of memory unlike Stack.Heap takes little longer to access and is able to hold bigger amount of data where data changes dynamically. The heap is the memory where the elements are not stored on top each other as it is done in stack but randomly, therefore each element has its own address. Reference values are primarily Objects and Arrays (Which are type of objects). To maintain Arrays and Objects in JavaScript we use both stack and heap together.
Below code snippet shows the object mutability.
// Reference Values ..
let testObject = {
name : 'Chandler',
age: 28,
address: 'New York'
};
let testObject1 = testObject;
console.log('testObject:', testObject.name); // Chandler
console.log('testObject1:', testObject1.name); // Chandler
testObject1.name = 'Janice';
console.log('testObject:', testObject.name); // Janice
console.log('testObject1:', testObject1.name); // Janice
Here, we see both objects contain same values associated with properties, this happens because objects are handled in a special way i.e. the memory block on stack holds memory address (pointer) of this object which is in turn stored in heap.
As we see in the above representation when an object is created by assignment, it does not allocate new memory block but creates a new pointer block and pushes onto the stack and both the pointers are pointing to the same place in the memory, resulting a change for variables pointing to elements place in memory.
Let’s see how arrays behave when altered.
// lets us check what if we push on Array
let testObject = {
name : 'Chandler',
age: 28,
address: 'New York',
friends: ['Monica', 'Ross', 'Joey']
};
let testObject1 = testObject;
testObject1.friends.push('Racheal');
console.log('testObject:', testObject.friends);
// ['Monica', 'Ross', 'Joey', 'Racheal']
console.log('testObject1:', testObject1.friends);
// ['Monica', 'Ross', 'Joey', 'Racheal']
We can achieve immutability in multiple ways
- ES5 Object.assign :
This method is used to copy the values of all enumerable own properties
from one or more source objects to a target object.
const testObject2 = Object.assign({}, testObject);
testObject2.name = 'Paul';
console.log(testObject.name); // Janice
console.log(testObject2.name); // Paul
- ES5 Array slice():
The slice() method returns a shallow copy of a portion of an array into
a new array object selected from begin to end (end not included) where
begin and end represent the index of items in that array. The original
array will not be modified.
const testObject2 = Object.assign({}, testObject);
testObject2.friends = testObject.friends.slice();
testObject2.friends.push('George');
console.log(testObject.friends);
// [ 'Monica', 'Ross', 'Joey', 'Racheal' ]
console.log(testObject2.friends);
// [ 'Monica', 'Ross', 'Joey', 'Racheal', 'George' ]
- ES6 spreadOperator:
This method copies own enumerable properties from a provided object into
a new object.
// ES6 spread operator for Objects.
let testObject = {
name : 'Chandler',
age: 28,
address: 'New York'
};
const testObject2 = {...testObject};
testObject2.name = 'Paul';
console.log('testObject:', testObject.name); // Janice
console.log('testObject1:', testObject2.name); // Paul
// ES6 operator for Arrays.
const testObject2 = {...testObject};
testObject2.friends = [...testObject.friends];
testObject2.friends.push('George');
console.log(testObject.friends);
//[ 'Monica', 'Ross', 'Joey', 'Racheal' ]
console.log(testObject2.friends);
//[ 'Monica', 'Ross', 'Joey', 'Racheal', 'George']
- UsingLoadash:
_.clone(value) –
This method creates a shallow copy of the provided value.
_.cloneDeep(value) –
This method is similar to clone except that it recursively clones the
value.
Note : By default all the methods except for _.cloneDeep create shallow copy of the data.
I hope with this article, I was able to differentiate between Primitive and Reference values.
If you find this article helpful and enjoyed it, feel free to share it with friends and colleagues.
Do you have any questions, suggestions or would like to reach to me? Drop me a message on linkedIn
Top comments (0)