Primitive and Reference Data Types in JavaScript

Patric
JavaScript in Plain English
5 min readMay 22, 2021

--

In the overview below, you see a list of primitive and reference data types, each with an example.

Let's take a closer look at the types before we point out the differences in terms of memory behavior.

You can check the data type of any variable with the typeof check.

let example = "hello";console.log(typeof example);
// outputs: > "string"

Primitive Data Types

Data Type null indicates that there is an object missing or invalid.

Special primitive type having additional usage for its value: if the object is not inherited, then null is shown;

let example = null;console.log(typeof example);
// outputs: > "object"

Data Type undefined as the naming indicated, the value is yet not defined.

let example;
let count = 6;
if (count > 7) {
example = "gets a value";
}
console.log(typeof example);
// outputs: > "undefined"

Data Type Boolean can only have two values true or false. It’s often used to write conditions to control the flow of a program.

let example = true;
if (example) {
example = false;
}
console.log(typeof example);
// outputs: > "boolean"

Data Type Number represents a floating-point number between (2⁵³ − 1) and 2⁵³ − 1).

let example = 33; // or something more precise 33.33console.log(typeof example);
// outputs: > "number"

Data Type String is a sequence of characters used to represent text for example letters, digits, special characters, and control characters.

let example = "hello";console.log(typeof example);
// outputs: > "string"

Data Type BigInt holds numeric values and is relevant if you need to work with very large numbers that exceed the safe integer limit for the Data Type Number. You can check the max safe integer for numbers with Number.MAX_SAFE_INTEGER

console.log(Number.MAX_SAFE_INTEGER);
// outputs: 9007199254740991
let example = 33n ** 33n;console.log(typeof example);
// outputs: > "bigint"
console.log(example);
// outputs: > 129110040087761027839616029934664535539337183380513n
let example2 = 33 ** 33; // number data typeconsole.log(example2);
// outputs: > 1.2911004008776101e+50
let example3 = 33 ** 33n; // number and bigint is not mixableconsole.log(example3);
// outputs: "Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions"

Data Type Symbol is a guaranteed way to ensure that the value is unique and immutable.

let example = Symbol("hello");console.log(typeof example);
// outputs: > "symbol"
let example2 = Symbol("hello");console.log(example === example2);
// outputs: > false

Reference Data Types

Data Type Object holds key-value pairs with a unordered collection of data and instructions. Can be created with new Object() or the literal syntax {}

let example = {hello: "world"}; // same as...
let example2 = new Object();
example2.hello = "world";
console.log(typeof example);
// outputs: > "object"
// console.dir gives you more insights about the inheritance in the // dev console -> see the image below
console.dir(example);

Data Type Function can encapsulate a piece of code and can be self inherited or called by other code.

// arrow functions are a compact alternative to function
let example = () => 2 + 2;
// same as...
function example2() {
return 2 + 2;
}
console.log(typeof example);
// outputs: > "function"
// insights about the inheritence and scopes -> see the image below
console.dir(example);

For more details about Data Types, please visit the very good documentation from Mozilla here.

Memory behavior of Primitive Types

For each primitive type, the value will always be saved separately, even if you save variable example into example2.

let example = "hello";
let example2 = example;
console.log(example);
console.log(example2);
// outputs: > "hello"
// outputs: > "hello"

The key point here is a change of the variable example would not affect example2, because the value is copied.

example = "hello world";console.log(example);
console.log(example2);
// outputs: > "hello world"
// outputs: > "hello"

Memory behavior of Reference Types

In contrast to primitive types, reference types like the name implies are only holding a reference to the value, in this example the object.

let example = {hello: "world"};
let example2 = example;
console.log(example);
console.log(example2);
// outputs: > {hello: "world"}
// outputs: > {hello: "world"}

The key point here is a change of the variable example does affect example2, because the value is only referenced.

example.additionalField = 33;console.log(example);
console.log(example2);
// outputs: > {hello: "world", additionalField: 33}
// outputs: > {hello: "world", additionalField: 33}

If you hand over your reference to a function, your original object is affected by changes.

let example = {hello: "world"};const exampleFunction = (object) => {
object.number = 33;

return object;
}
exampleFunction(example);console.log(example);
// outputs: > {hello: "world", number: 33}

You can easily solve this by using the spread operator and save a copy into a new variable. You can read more about the spread operator here.

let example = {hello: "world"};const exampleFunction = (object) => {
const newObject = {...object};
newObject.number = 333;
console.log(newObject);

return object;
}
exampleFunction(example);console.log(example);
// outputs: > {hello: "world", number: 33}
// outputs: > {hello: "world"}

Keep in mind that almost everything you make with the new keyword is an instance of an object, also arrays no matter if you create them by calling new Array() or just [].

I hope I gave a well-rounded introduction to primitive and reference types. Your welcome to write any questions in the comments!

More content at plainenglish.io

--

--

Loving web development and learning something new. Always curious about new tools and ideas.