Book of Coding


Difference between primitive data types and reference types

The difference between primitive data types and reference types is the way in which the respective values are stored. Each time a variable is declared, the computer allocates memory space for it and stores the variable and its value in a memory address provided for this purpose.


1. The principle of primitive data types

With primitive data types, every time a value is assigned to a variable, the entire value is copied to this memory address. For example, if a variable x is created via let x = 5;, the computer saves this variable internally and stores the value 5.


 let x = 5;          // x --> 5
                        

If the instruction let y = x; is now executed, the value of x (5) is assigned to the variable y. Internally, the computer copies this value into the register intended for the variable.


 let x = 5;          // x --> 5
 let y = x;          // y --> 5
                        

2. The principle of reference types

The situation is slightly different with reference types. Here, the computer does not store the value itself in the register provided for the respective variable, but only a reference to it (also called a pointer).


 let x = 5;          // x --> 5
 let y = x;          // y --> 5

 let rick = {                // rick
     firstName: 'Rick',      // firstName Rick
     lastName: 'Sample'      // lastName Sample
 }

 let rick2 = rick;
                        

The variable rick is initialized here with an object, i.e. a reference type. However, this object, which is composed of various primitive data types, is not stored directly in the register, but only referenced via a pointer.

If you now create a second variable (rick2) and assign the content of the variable rick to it, it is not the object stored there that is copied, but the pointer to the object. Both variables then point to the same object.


 let x = 5;          // x --> 5
 let y = x;          // y --> 5

 let rick = {                // rick
     firstName: 'Rick',      // firstName Rick
     lastName: 'Sample'      // lastName Sample
 }

 let rick2 = rick;           // --> rick2 --> firstName Rick, lastName Sample
                        

If two or more variables point to the same object, as in the example, this also means that you always work with the same object, regardless of which variables you access. So if you change a property of the referenced object via one of the variables, this also has an effect on the other variable:


 let x = 5;          // x --> 5
 let y = x;          // y --> 5

 let rick = {                // rick
     firstName: 'Rick',      // firstName Morty
     lastName: 'Sample'      // lastName Sample
 }

 let rick2 = rick;           // --> rick2 --> firstName Morty, lastName Sample

 rick2.firstName = 'Morty'
                        

Access to object properties and object methods via dot notation:


 const rick = {
   firstName: 'Rick',
   lastName: 'Sample'
 }
 const rick2 = rick;
 rick2.firstName = 'Morty';
 console.log(rick2.firstName); // "Morty"
 console.log(rick.firstName);  // "Morty"
                        

3. Primitive data types and reference types as function arguments

If arguments of a primitive data type are passed to a function, for example the number 420, the values are copied to the corresponding parameters of the function. If you change the value of a parameter within the function, this does not change the value of the variable that was passed to the function as an argument.

Complete Code - Examples/Part_112/main.js...

 function example(x) {
   console.log(x);           // 420
   x = 6;
   console.log(x);           // 420
 }
 let y = 420;
 console.log(y);             // 6
 example(y);
 console.log(y);             // 420
                        

Here, the variable y is first initialized with the value 420 and then passed to the function example(). Within this function, the parameter x is set to the value 6. However, this does not change the value of y.

If you change the example and replace the variable y and the parameter x with an object, the behavior is different. If you now pass the variable y as an argument to the function example(), you pass the pointer to the object that is assigned to the variable y. Within the function, x now also points to this object. This means that if you change a property on x, you change the same object that y points to:

Complete Code - Examples/Part_113/main.js...

 function example(x) {
   console.log(x.value);         // 420
   x.value = 6;
   console.log(x.value);         // 420
 }
 let y = {
   value: 420
 };
 console.log(y.value);           // 6
 example(y);
 console.log(y.value);           // 6
                        

4. Determine the type of a variable

As the type of a variable is not specified in the declaration, the question arises as to how to recognize it. This is possible using the typeof operator. This is a unary operator, i.e. it only expects an operand for which the type is to be determined. The operator returns a character string as the return value.

Return value of the typeof operatorReturned for...
boolean boolean values
number numeric values
string character string
symbol symbols
function functions
object all types of objects and the value null
undefined undefined variables

Application of the typeof operator for different values


 console.log(typeof true);               // boolean
 console.log(typeof false);              // boolean
 console.log(typeof 420);                // number
 console.log(typeof 42.42);              // number
 console.log(typeof 'Rick Sample');      // string
 console.log(typeof function () {});     // function   
 console.log(typeof {});                 // object
 console.log(typeof []);                 // object
 console.log(typeof null);               // object
 console.log(typeof undefined);          // undefined
 console.log(typeof Symbol('ยง'));        // symbol
                            

In addition to the typeof operator, there is another operator that has something to do with determining the type of variables, namely the instanceof operator. The operator returns a Boolean value.

The object rick is of type Object, but not of type Array. The object numbers, on the other hand, is of both type Object and type Array. This is because the type Array is a "lower type" of Object in JavaScript. The type of functions, Function, is also a "lower type" of "Object", so that the instanceof operator for the function add() returns true in both cases:


 const rick = {
   firstName: 'Rick',
   lastName: 'Sample'
 }
 const numbers = [2,3,4,5,6,7,8,9];
 function add(x, y) {
   return x + y;
 }
 console.log(rick instanceof Object);        // true
 console.log(rick instanceof Array);         // false
 console.log(numbers instanceof Object);     // true
 console.log(numbers instanceof Array);      // true
 console.log(add instanceof Function);       // true
 console.log(add instanceof Object);         // true
                            

Object is the type from which all other reference types are derived. The instanceof operator therefore returns the value true for all variables of any reference type.

In contrast to the typeof operator, the instanceof operator only works for values that contain a reference type. For values of primitive data types, on the other hand, the operator always returns false:


 console.log(true instanceof Object);                // false
 console.log(420 instanceof Object);                 // false
 console.log('Rick Sample' instanceof Object);       // false
                            

Note

To check whether a variable is an array, the Array.isArray() method is available as an alternative to the instanceof operator:


 const rick = {
   firstName: 'Rick',
   lastName: 'Sample'
 }
 const numbers = [2, 3, 4, 5, 6, 7, 8, 9];
 console.log(Array.isArray(rick));            // false
 console.log(Array.isArray(numbers));         // true
                                

Related links: