Responsive Advertisement

JavaScript #7: Value types and reference types in JavaScript

                                    

Value types or referene types is making it difficult for you to approach JavaScript. Or you already have a lot of experience and want to revisit this concept. This is an article to help you strengthen your knowledge about value types and reference types.

The goal of the article is to help you understand the concept of value types and reference types. From this, it is possible to distinguish these two concepts. Makes coding or bug fixing easier.

Table of contents:

·       What is value types?

·       What is reference types?

·       Work with reference type

Let’s go to the content!

What is value types?

First, let's go over the concept of primative variables in JavaScript. In JavaScript has basic data types. These data types are not Object (Array, Object) and have no method.

There are seven types of premative variables in JavaScript including: string, number, undefined, symbol (ES6), bigint, boolean, null.

All primative variables are immuable. It's mean can't be alter. Variables can be assigned a new value, but no method of array or object can be used to change the value.

Once you have a solid understanding of primative variables in JavaScript. We can say that primative variables are value types. Let's see the example to understand better:

let a = 0

let b = a

a = 5

 

// What is a ?

// What is b ?

Would you answer this question something like this?

First, we initialize let a = 0. The variable a is having the value = 0. We initialize let b = a. Now the variable b is having the value = a and = 0. Then we assign it again to a = 5. And finally, a has the value = 5 and b has the value = 0. Let's see if the result is like we explain.

let a = 0

let b = a

a = 5

 

console.log(a) // => 5

console.log(b) // => 0

Completely correct with the above explanation.

Let's go deeper to understand how the engine in JavaScript works. First, when creating variable a, the system will allocate a separate memory area, name this memory area 0x00a. And the memory area 0x00a is storing the value 0. Then, we initialize the variable b = a, the system will continue to allocate another memory area. This memory area let's name it 0x00b and is storing the value is equal to the variable a = 0. Then we change the value of the variable a to 5. It means that the memory area 0x00a is storing the value as 5. Let's see the table below to summarize.

Variables

Address

Value

a

0x00a

0

b

0x00b

0

a = 5

0x00a

5

When we change the value of variable a, then the value of memory 0x00a will change. Memory 0x00b is not affected. So, when we print the result, changing the variable a does not affect the variable b at all.

To make this more clear, let's see the example below:

let a = 0

let b = 0

 

console.log(a === b) // =>  true

 

let c = 0

let d = c

 

console.log(c === d) // => true

Through the above example we can say, the variables have the same value even though they are in different memory areas. And the engine in JavaScript uses === to compare values ​​and data types, then we have returned results that are completely correct.

What is reference types?

We can see that all primative variables are value types. So that means the remaining objects will be reference types. We have Object, Array, Function as reference types.

Let's go through a similar example above to see the difference:

let david = {

    name: 'David'

}

 

let oliver = david

 

oliver.name = 'Oliver'

 

console.log(oliver.name) // => What is the result ?

console.log(david.name) // => What is the result ?

Let's analyze to predict the outcome. We instantiate a let david object and assign it a value of “name: 'David'”. We continue to instantiate a let oliver object and assign it to the value of the david object which means that the oliver object has the value name: 'David'. We change the name value of the oliver object to 'Oliver'. Finally, the result will return oliver.name === 'Oliver' and david.name === 'David'. Let's see the results:

let david = {

    name: 'David'

}

 

let oliver = david

 

oliver.name = 'Oliver'

 

console.log(oliver.name) // => Oliver

console.log(david.name) // => Oliver

Wow! Unexpectedly, things did not go as we expected. Let's analyze to find out what's going on.

When we first create the david object, the system also creates a memory area and stores the value { name: 'David' }. Name this memory address 0x00david. The variable david when created has the value of the name of the memory address 0x00david, not the value { name: 'David' }. Then we create the oliver object equal to david. Now the value of the oliver variable will be equal to the address of the memory area which is 0x00david and not {name: 'David'} at all. That means david and oliver are pointing to the same memory area. When we change the value of oliver.name, it also means that we are changing the common value of the two objects, so when we log the results, we see that both have the same result. Check out the table below for a summary.

Variables

Address

Values of address

Values of variables

David

0x00david

{name: ‘david’}

0x00david

Oliver

0x00david

{name: ‘david’}

0x00david

Oliver.name = ‘oliver’

0x00david

{name: ‘oliver’}

0x00david

We can come to the conclusion that the object when created will be assigned the storage address of the value, not the value.

At the same time, creating a new object will create a new memory area. Let's see the example below:

let a = {}

let b = {}

 

console.log(a === b) // => false

As discussed above, let a and let b only store the address of the created object. Although the two values ​​are the same. But when comparing let a and let b we are only comparing two addresses, not comparing two values. Check out the summary below:

Variables

Address

Values of address

Values

a

0x00a

{ }

0x00a

b

0x00b

{ }

0x00b

We see that the values ​​in the two memory areas are the same. But the value that the two variables are storing is the address where the values ​​are stored.

And through the example above we can see how many objects are created, how much memory is created. No matter how many times objects are nested. Let's see an example to understand better:

let parent = {

    dad: 'Dad',

    mom: 'Mom',

    child: {

        name: 'child'

    }

}

 

let otherChild = parent.child

 

otherChild.name = 'otherChild'

 

console.log(parent)

// => Object { dad: "Dad", mom: "Mom", child: { name: 'otherChild } }

console.log(otherChild)

// => Object { name: "otherChild" }

We only change the value in the memory area, not the memory address. So when called from any source will only change the value there.

Work with reference types

Do you think that now you want to change the value in that memory area but not affect other objects that are refering to that memory area, what will happen? I have the following 2 ways for 2 cases, you can refer and apply,

Case 1: For a single-level object

const user = {

    name: 'User name',

    pasword: 'Password'

}

 

const otherUser = { ...user }

 

otherUser.name = 'Another user name'

 

console.log(user.name) // => User name

console.log(otherUser.name) // => Another user name

This means you are creating a new memory area for the otherUser variable. So, when you change the value of otherUser, the user is not affected. This is how you do it when you want to copy an object without changing the original object.

Case 2: For a muti-level object

The above method is only applicable to single-layer Objects. Let's go through the limitation in the first way:

const user = {

    name: 'User name',

    pasword: 'Password',

    account: {

        balance: '$1000'

    }

}

 

cosnt otherUser = { ...user }

 

otherUser.account.balance = '$2000'

 

console.log(user.account.balance) // => $2000

console.log(otherUser.account.balance) // => $2000

As you have seen, you will change the value of both objects. This is something you don't want at all. Let's go through the second way to apply in this case.

 const user = {

    name: 'User name',

    pasword: 'Password',

    account: {

        balance: '$1000'

    }

}

 

const otherUser = JSON.parse(JSON.stringify(user))

 

otherUser.account.balance = '$2000'

 

console.log(user.account.balance) // => $1000

console.log(otherUser.account.balance) // => $2000

 

Work! The main point in both ways above is that the newly created object creates a new memory pool. And the fact that you change the value in separate memory areas can't affect each other.

Another case:

You will wonder that in the above cases, I use const to initialize but why can I change the values. Is the theory of const in this case wrong?

The theory of const is always true in this case. Because I only change the value in the memory area, not the address that the variable is pointing to. So, I can change the values ​​inside that memory.

Conclusion

You have come across the concept of premative variables as value types. The rest are reference types. Value types is a variable that when created will store the value. And when the reference types is created, the variable stores the address to that memory area. How to deal with reference types.

If you have any comments, feel free to comment below. Thank you for joining with me. Have a good day!


Đăng nhận xét

0 Nhận xét