Javascript differentiates Data Types on :
- Primitive Types (Number, String, Boolean, null & undefined).
- Complex Types (Objeccts & Arrays).
Copying Primitive Values :
When copying primitive values, Javascript is going to behave as we expect it to. We just need to see what was the value of the variable at the time of the assignment.
Copying Numbers:
let x = 10;
let y = x;
x = 2;
console.log(x); // 2
console.log(y); // 1
Copying Strings :
let name = "John";
let copiedName = name;
name = "Peter";
console.log(name); // John
console.log(copiedName); // Peter
- As you can see the value of
y
&copiedName
doesn't changed / updated, because they were assigned before updating the respective original values. - It means
x
was assigned toy
when it's value was1
&name
was assigned tocopiedName
when it's value wasJohn
. - Since,
Primitive Types / Values
are referred to asPass-By-Value
, they justremember / store
the value that was assigned to them at the time ofinitialization
, & later if theoriginal value
(x
,name
) gets updated, this doesn't affect thenew values
(y
,copiedName
) because they are notsubscribed
to original values`.
Copying Complex Values :
When copying complex values, Javascript engine is not going to behave as you initially think it would.
Copying Arrays :
const games = [ 'cricket', 'football' ];
const copiedGames= games;
games.push('tennis');
console.log(games); // [ 'cricket', 'football', 'tennis' ]
console.log(copiedGames); // [ 'cricket', 'football', 'tennis' ]
- As you can see the
games
&copiedGames
returns thesame array
, but in the case ofprimitive values
we got the different output. - Lets try with
Objects
.
Copying Objects :
const person = {
firstName : "John",
lastName : "Cena"
}
const newPerson = person;
// Change the firstName
person.firstName("Jane");
console.log(preson); // { firstName : "Jane", lastName : "Cena" }
console.log(newPerson); // { firstName : "Jane", lastName : "Cena" }
- Again, we got the same
object values
in-case ofcopmlex types
. - So, lets see what's happenning...
When a variable is assigned a
primitive value
, it just copies that value. We saw that withnumber
andstrings
examples.On the other hand, when a variable is assigned a
non-primitive value
(such as an object, an array or a function), it is given areference
to that object’s location inmemory
. What does that mean?
In this example above, the variable newPerson
doesn’t actually contain the value { firstName: 'John', lastName: 'Cena' }
, instead it points to a location in memory
where that value is stored.
const person = {
firstName : "John",
lastName : "Cena"
}; // memory-location :- bca154
const newPerson = person; // memory-location :- bca154
- Since, the
Complex Types / Values
are referred to asPass-By-Reference
, When a reference type value is copied to another variable, likenewPerson
in the example above, the object is copied by reference instead of value. In simple terms,person
&newPerson
don’t have their own copy of the value. They point to the same location in memory, for ex:memory-location :- bca154
.
// Change the firstName
person.firstName = "Jane";
console.log(preson); // { firstName : "Jane", lastName : "Cena" }
console.log(newPerson); // { firstName : "Jane", lastName : "Cena" }
When a new item is pushed to
person
, the array in memory is modified, and as a result the variablenewPerson
also reflects that change.We're never actually making a copy of a
person
object. We're just make a variable that points to the same location in the memory.
Equality
- Since the two variables are returning the same value, lets check by creating two variables with same values & check their
equality
.
const personOne = {name : "John"}; // memory-location :- bca112
const personTwo = {name: "John"};
console.log(personOne === personTwo); // memory-location :- bca155
- Here, both the variables
personOne
&personTwo
have the same values, lets check what we get!
console.log(personOne === personTwo); // false
// since bca112 !== bca155
- You might thought that
equality
of these variablespersonOne
&personTwo
logstrue
, but that isn't true. The reason behind that is that although person & otherPerson contain identical objects, they still point to two distinct objects stored in different locations in memory. - Now, let's create a copy of the person object by copying the object itself, rather than creating a completely new instance of it.
const anotherPerson = personOne;
console.log(anotherPerson === personOne); // true
personOne
&anotherPerson
hold reference to the same location in memory & are therefore considered to be equal.Awesome! We just learned that primitive values are copied by value, and that objects are copied by reference.
- But, how to make a real copy of an object & remove it's
reference
. That will allow us to copy an object and change it without being afraid that we'll change both objects at the same time.
Shallow Cloning :
Cloning Arrays :
- There are 2 ways to
shallow-clone / copy
an array.
- Spread Operator
- array.slice()
Spread Operator
- Lets create an array of numbers & copy the original array without it's
reference
.
const numbers = [ 1, 2, 3];
const copiedNumbers = [ ...numbers ];
// this is how we add `spread opertor` in an array
console.log(numbers); // [1, 2, 3]
console.log(copiedNumbers); // [1, 2, 3 ]
- Now lets try to
update
the original array(numbers
) & log both the arrays to see if thecopiedNumbers
array alsoupdated
. Let us also check theequality
between them.
numbers.push(4,5);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(copiedNumbers); // [1, 2, 3 ]
console.log(numbers === copiedNumbers); // false
- Now we get different
outputs
, since their reference isdifferent
. It means we have successfully copied theoriginal array
without it's actualreference
. - Hence, change in any of the arrays doesn't reflect to both the arrays.
array.slice()
const numbers = [ 1, 2, 3];
const copiedNumbers = numbers.slice();
// slice() returns shallow copy of some portion of array based upon the arguments passed to it.
numbers.push(4,5);
console.log(numbers); // [1, 2, 3, 4, 5]
console.log(copiedNumbers); // [1, 2, 3 ]
Cloning Objects :
- There are 2 ways to
shallow-clone / copy
an object.
- Spread Operator
- Object.assign()
Spread Operator
- Lets create an
person object
& copy the originalobject
without it'sreference
.
const person = {
name: 'Jon',
age: 20,
};
const otherPerson = { ...person };
otherPerson.age = 21;
console.log(person); // {name : "Jon", age : 20 }
console.log(otherPerson); // {name : "Jon", age : 21 }
Object.assign() :
const value= { a: 2 };
const copiedValue= Object.assign({}, value);
// Object.assign() works same as the spread operator.
Deep Cloning :
- Let's try creating a copy of that object, by adding
nested obect
to it.
const person = {
firstName: 'Emma',
car: {
brand: 'BMW',
color: 'blue',
wheels: 4,
}
};
const copiedPerson = { ...person };
person.firstName = "Watson";
console.log(person.firstName);
console.log(copiedPerson.firstName);
- Cool, as always we both the objects retun distinct values.
- Now lets try to change the value of the
nested
object (car
) & see what that logs.
person.car.color = "red";
console.log(person.car.color);
console.log(copiedPerson.car.color);
- Oops, We've got the same color
red
in both the objects(person
&copiedPerson
). This is because thespread operator
just copies thefirst level
of the object. That's why this method namedshallow cloning
. - So, to remove
reference
from the nested object, we have to again performspread operation
on thenested object
(car
). If there aren-number of
nested objects, then we have to performspread operation
to all thosenested objects
as-well. This isTricky
right!! - So, to avoid that level of difficulty, we have
Deep Cloning
. Deep Cloning
can be achieved by using2
methods.
- JSON.stringify()
JSON.parse()
Lets apply this in our previous
person
object & change thebrand
this time.
const person = {
firstName: 'Emma',
car: {
brand: 'BMW',
color: 'blue',
wheels: 4,
}
};
const stringifiedObject = JSON.parse(JSON.stringify(person));
person.car.brand = "AUDI";
console.log(person.car.brand); // "AUDI"
console.log(stringifiedObject.car.brand); // "BMW"
- Hence, Now we get two different values of
brand
in nested object. Thus,Deep Cloning
ishelpful
&easier
forremoving-reference-from-reference-types
.Conclusion :
- For the objects with
one-level-nesting
,spread operator
will be okay, but for theobjects
with more than one level nestingDeep Cloning
will be efficient for destroying all the references.
--> If you like this blog
, feel free to like
, comment
& share
with your friends.
--> If there is any thing to be corrected, plz mention in the comment section below, I would appreciate that.