Primitives are passed by value. Objects are passed by reference.
If we want to change them, we have to completely remove them from memory.
We saw that if we have var a =7;
In order for me to change what 7 is, I have to remove it from memory and create something new like var a =10.
So I can’t really modify it. Something new just gets created.
This is the nature of primitive types. When I assign var a=7, somewhere in memory, var a is going to contain and reference the value 7.
If I do var b =10, somewhere in memory, var b is going to contain and reference the value 10.
var a = 7;
var b = 10;
These two don’t really know of the existence of the other. This is what we call passed by value.
Difference between passed by reference & passed by value. Source: ZTM Academy
Objects, on the other hand, are passed by reference.
If I do:
var a =1;
var b =2;
We know that a now has an address of where this primitive value 1 sits in memory, and b has an address of where the primitive value 2 sits in memory.
That’s what passed by value means. It simply means we copy the value and we create that value somewhere else in memory.
But what if I do var b = a
What happens then?
Remember, primitive types are passed by value.
Our results above are due to what's known as pass by value.
All we did was copy the value.
So our diagram above should make sense. Every time we did b=a, we simply copied the value of a and put it into a new memory space in our machine.
That's what passed by value means. It simply means we copy the value and we create that value somewhere else in memory.
How are objects different?
If I create an object:
obj2 and obj1 are the same.
And if I go and change the password for obj2 to 456?
Let's see what happens?
We see that both obj1 password and obj2 passwords have been changed to 456.
This is because of Pass by Reference.
When we assigned obj1 = obj2, we simply said, hey, this is where the obj is in memory. So obj1 and obj2 are both pointing somewhere in the memory heap to the shelf that contains this information.
More simply put:
obj2=> obj address in memory <=obj1
Changing obj. password meant changing the object password in memory — the same object in memory that also obj1 is pointing to or referencing. And that's where the term pass by reference comes from.
So why is this a good idea?
By just having one object for obj1 and obj2, we are saving memory.
We are not copying and cloning the object to create multiple versions. We simply reference just one location instead of just loading up our memory heap.
And why is this bad?
Because unlike a primitive type, we can have a situation where someone accidentally changes a property on the referenced object.
So we need extra caution here.
Now previously we have said that arrays are objects. So let's demonstrate pass by reference using arrays and at the same time confirm that indeed arrays are objects.
d now has c values and the new number
We see that we modified the array. But because arrays are objects, they are passed by reference. So c should also have changed.
Pass by reference: c has changed after changing d.
This is good. We are saving memory. We are not constantly copying things.
Because just imagine if c was a massive object; if we are copying to different memory spaces every time, we would use up a lot of memory.
But how about the times when we just want to clone an object — just copying it so that we don't modify the original object?
How can we do that?
With an array, there are different ways of doing it. We can say:
This pushes whatever I have in c into the array and preserves the original array.
d is a cloned array.
Now Objects are a little bit difficult.
Let's say we have an object:
This is the object I want to copy. I want to have it in a different part of memory.
I can't just do:
let obj2= obj;
Because its simply going to pass by reference — we are still going to be referencing the same object.
Instead, we can clone an object.
The first parameter is where to copy to and the second is the source.
So that now if I change obj.c = 5;
If I console.log(clone), we see that the cloned object was not affected even though we changed c to be 5.
Remember if we didn’t clone obj, it would have been passed by reference.
We can also use the spread operator.
The spread operator came with Es6 and its very helpful.
So cloning is great. But what do you think will happen if we have an object inside of an object?
Here we have an obj that is referenced somewhere in memory and inside of that obj, there is again another pointer to another place in memory that references this object.
When we run this code, we see that nothing has changed.
But what if I change obj.c.deep = ‘hahaha’? What is going to happen here?
We see that even though we cloned everything, it all got overwritten.
So what could be the explanation here?
Its important here to remember that each object gets passed by reference. So although we cloned the initial obj, it was a shallow clone. We cloned the first level — that is the memory address in this obj.
But within this obj, there was another address to another object. This address never changed. It always referenced the new object.
Now it's obvious that this is a problem and the way we solve it is if we do deep clone.
For that we use JSON.
Here, we are turning everything into a string. Once that's done and we have everything as a string, we parse it and turn that string into an object.
So that if I do console.log(superClone), I get a deep clone of the obj.
Now, this can have performance implications. For instance, if this obj was extremely deep — a massive object, it would take a long time to clone everything.
That means that if you ever find yourself in a situation where you need to clone objects this way, there is likely another way you should be doing things.
Technology will save homo sapiens from extinction