What are data types?

Computer programs generally deal with a lot of data. This data can be of several types. Each type has its own purpose, utilities, and underlying mechanism of implementation.

Some are primitive types, where some are object types, also known as reference types.

In this chapter, we shall get an overview of the data types JavaScript comes equipped with, out-of-the-box. We'll explore the six most common primitive types and the three most common reference types. Moreover, we'll also consider the typeof operator, which is used to inpsect the type of a given value.

The basic understanding is imperative for you as you move on to learn tons and tons of additional concepts in JavaScript. In the coming units, we'll go over each of these types one-by-one in the finest of details.

So without wasting any more time, let's get straight into work.

Primitives and objects

JavaScript divides data essentially into two main categories: primitives and objects.

Let's start by defining what a primitive is:

A primitive is a value without any properties/methods attached to it.

It's basically the simplest form of data in JavaScript. It depicts the lowest-level implementation of a piece of data.

The simplest example would be numbers.

Consider the value 10. This is a number, and most importantly, a primitive. There are no properties or methods attached to 10 in JavaScript.

10 directly represents a number stored in memory. There is not something else stored in a variable holding a number — the number is directly stored inside the variable.

However, this doesn't apply to objects — when an object is stored in a variable, something else is stored inside the variable instead of the object directly. We'll see details to this later on in this chapter.

Recall the document and console objects from the previous chapters? Recall their write() and log() methods, respectively?

Since document and console both have a method attached to them (actually, they have many methods), we say that they are NOT primitives.

JavaScript comes equipped with five primitive data types: numbers, strings, Booleans, undefined and null.

Strictly speaking, there are seven primitive types in JavaScript — 5 that are mentioned above and the remaining two as follows: symbols and bigint.

On the other hand, an object is the mirror image of a primitive:

An object is a value with properties/methods attached to it.

An object type is also commonly referred to as a reference type. By that means, objects are also called references.

Simply put, if a value isn't a primitive, then it is an object.

Apart form the five primitive data types discussed above, everything else is an object.

Functions are a special category of objects, commonly known as callable objects. We'll learn more about functions in the following sections.

The most interesting distinction between primitives and objects is that the former is passed by value, while the latter is passed by reference. Primitives are copied and then passed over to variables; whereas objects aren't copied themselves, but rather their references are.

You'll learn more on passing by value vs. passing by reference in the Values and References chapter.

Let's start by exploring each of the five primitive types in JavaScript before heading over to consider some of the most common object types.

Primitive data types

We'll go over each of the primitive types one-by-one, starting with numbers.

Numbers

Numbers are everywhere when it comes to computing — they are used in arithmetic calculations, computer algorithms, data science, 3D modeling, transformations, and much more..

In programming, generally numbers are categorised into two groups — integers and floats.

An integer is a whole number without a decimal point.

Examples include 0, 1, 100. A minus sign (-) can be included before the number to denote a negative integer. Examples include -30, -50, -100.

Integers are sometimes also referred to as fixed-point numbers.

Similarly,

A float is a number with a decimal point.

Example include 0.1, 3.878, -4589.4 and so on.

Floats are sometimes also referred to completely as floating-point numbers.

Some programming languages, such as Python, actually make this distinction between numbers by providing individual types for them.

However, JavaScript doesn't make any distinction between integers or floats whatsoever — we've got only one type for numbers in the language and that is Number.

In the snippet below we play around with a couple of numbers:

2 + 2
4
2 + 2.5
4.5
2.5 + 2.5
5
2.5 - 2
0.5
2 - 20
-18

All the numbers shown above are known as number literals.

What is a literal?

A literal is an exact representation for a value in the code.
We will go over numbers in detail in the JavaScript Numbers unit.

Strings

Another extremely common data type in JavaScript, and nearly all programming languages, is the string type.

A string is a sequence of textual characters.

It can contain alphanumeric characters, symbols, spaces, newlines, emoticons, characters from other languages etc.

A string can be denoted using a pair of single quotes (''), or a pair of double quotes ("").

The following code show two strings:

var lang = 'JavaScript'; // single quotes
var os = "Windows"; // double quotes

The first string is stored in the variable lang while the second one is stored in os.

There is yet a third way to denote variables and that is using a pair of backticks (``). Such strings are called template literals and could contain JavaScript expressions within them. We'll explore more on template literals in JavaScript String Basics.

Each character in a string sits at a given position, formally known as its index. Indexes begin at 0. This means that the first character is at index 0, the second one is at 1 and so on and so forth.

The total number of characters in a string is referred to as its length.

To access a given character in a string, we start by writing the string followed by a pair of square brackets ([]), and within them mention the index of the character, as an integer.

Consider the snippet below:

lang[0]
'J'
os[2]
'v'

In the first statement lang[0], we access the first character of lang by putting the number 0 inside the square brackets. Similarly, in the second statement os[2], we access the third character of the string os by writing the number 2 inside the brackets.

To get the length of a given string, we access its length property.

The syntax to access a property is easy: start by writing the value whose property you want to access, followed by a period character (.), followed by the name of the property.

Consider the snippet below where we access the length property on the strings lang and os defined above:

lang.length
10
os.length
7

Booleans

The third in this list is Booleans.

A Boolean is simply a true or false value.

Booleans are used extensively in conditional programming to control program flow by making decisions on the outcomes of given evaluations.

The name Boolean is given in honour to the notable British mathematician, George Boole, who made many important contributions to modern-day Boolean algebra and logic. He is called the 'father of symbolic logic'.

In JavaScript, a Boolean is denoted using the literal values true and false.

The following code creates two Boolean variables:

var proceed = true;
var stopNow = false;
We will go over Booleans and their applications in detail in the JavaScript Booleans chapter.

Object data types

Let's now go over some of the most common object types in JavaScript.

Arrays

The first data type to explore is arrays.

An array is an ordered collection of data, stored at contiguous positions known as indexes.

An array is like a list of values. Each value in the list sits at a given position, formally known as its index.

An array has the capability of storing multiple values under one hood. The individual values of an array are formally called elements.

Array elements can be of any data type. They could be number, strings, Booleans — simply anything. They could even be arrays. We'll explore such cases in detail in the JavaScript Arrays Basics chapter.

Moreover, it's not required for the elements of an array to be of the same data type. An array could for example contains numbers and strings.

Strings and arrays are both sequences of data. Whenever dealing with a sequence in JavaScript, remember that each element of the sequence sits at a given position in the sequence, known as its index.

Let's now see how to create an array.

An array could be denoted literally using a pair of square brackets ([]). Each element of the array goes within the brackets, and is separated from another element using a comma (,).

The following code shows an array nums created using literal notation:

var nums = [1, 5, 10];

Accessing a given element from an array follows the same syntax accessing a character from a string does.

That is, we start by writing the array value, followed by a pair of square brackets ([]), and then put the index of the element, we wish to access, inside these brackets.

Below we access the first and last numbers in the nums array:

nums[0]
1
nums[2]
10

As with strings, we could obtain the total number of elements in an array using its length property.

Let's see what gets returned by accessing the property on our nums array:

nums.length
3

As expected, we get 3, which rightly aligns with the total number of items in nums.

Storing and merely retrieving values from an array isn't interesting, and usually not what happens in applications where arrays are used.

When arrays are used, they are often processed.

One common operation performed on arrays is sorting. This is accomplished using the array method sort().

The sort() method sorts the elements of an array alphabetically.

It converts each element into a string, and then performs the comparisons between the resulting values to determine which one would come first, which one would come second and so on.

Note that sort() sorts a given array in-place. This means that the actual array is modified in the sorting operation. This is one example to show that an array is a mutable data type.

Consider the following code:

var langs = ['Python', 'JavaScript', 'C++', 'C', 'Java'];

langs.sort();

console.log(langs);

First, we define a variable langs and assign an array value to it. Next, we call the sort() method on this langs array. This sorts the items in it in alphabetical order. Finally, we log the array.

["C", "C++", "Java", "JavaScript", "Python"]

See how each subsequent value in this sorted list is alphabetically larger than the previous value.

Owing to the fact that sort(), by default, converts each value in the respective array into a string before the sorting routine, we couldn't sort numbers correctly using this method, as is.

Consider the following snippet. See how the numbers are arranged in the sorted list:

[100, 9, 80, 2, 0, -1, -50].sort()
[-1, -50, 0, 100, 2, 80, 9]

-1 appears before -50 even though it is greater than -50. Similarly, 100 appears before 2, while 80 appears before 9 and after 100. It's just a total mess!

To sort numbers correctly using sort(), we have to pass it an argument that specifies the way in which to sort the elements. This argument needs to be a function.

Consider the following snippet:

[100, 9, 80, 2, 0, -1, -50].sort(function(a, b) { return a - b; })
[-50, -1, 0, 2, 9, 80, 100]

This time, the sorted array has the given elements arranged correctly, thanks to the function provided as argument.

We'll explain how this argument function works in the section below when we go over the function data type.

Functions

No programmer can negate the importance of functions in programming — they play an integral role. Some programming languages are largely built upon the idea of functions. Some consider functions on the same lines as other values.

JavaScript is an instance. Such languages are known as functional languages.

At the core, the idea of a function is elementary, however extremely powerful.

Let's define what a function is:

A function defines a piece of code that gets executed when the function is called.

In programming terminology, we use the word 'invoke' instead of 'call'.

Functions could be named or anonymous. For now, we are concerned with the former.

To create a function in JavaScript, we use the function keyword. Shown below is the syntax of creating a function:

function functionName(parameterList) statement;

We start with the function keyword, followed by the name of the function. This name defines an identifier and should likewise follow the variable naming rules of JavaScript.

After this, comes a pair of parentheses (()) and within them the parameters of the function. We'll see what are parameters later on in this section.

Finally comes a statement for the function. This statement is formally known as the function's body.

As a whole, the code defining a function is referred to as the function's definition.

The body of a function executes as soon as the function is called.

To call a function, we simply write its name followed by a pair of parentheses. This pair of parentheses serves to call, and likewise execute, a function. Without the parentheses, we simply refer to the function's definition.

Alright, a lot of theory has been discussed — it's time for an example.

In the code below, we create a function sayHello() to greet the user:

function sayHello() {
    var name = prompt('Enter your name:');
    document.write('Hello, ' + name + '.');
}

Inside the function, first we ask for the user's name via prompt() and then output the greeting message via document.write() with the input name included.

Let's call this function.

function sayHello() {
    var name = prompt('Enter your name:');
    document.write('Hello, ' + name + '.');
}

sayHello();

The last statement here calls sayHello() i.e. executes the code defined inside sayHello.

Moving on, a function can take additional data to perform its task.

For instance, a function made to add two numbers together might accept those numbers as additional data when calling the function.

Such additional pieces of data are called arguments, or simply args. Arguments to a function go inside the pair of parentheses when calling the function.

The name with which we refer to each argument inside the function is called a parameter. Parameters go inside the pair of parentheses when defining a function.

By that means,

A parameter is the name with which we refer to a value passed to a function while an argument is the actual value.

You'll see the terms 'arguments' and 'parameters' used interchangeably out there, which is strictly not completely wrong. However, it's good to know of this formal distinction between these terms.

Let's define a function sum() that takes in two numbers and outputs their sum on the document:

function (a, b) {
    console.log(a + b);
}

This function has two parameters a and b. Conventionally, throughout this course, whenever referring to parameters, we'll italicize them to rightaway indicate that they are parameters.

Anyways, let's call this function with a couple of arguments:

function sum(a, b) {
    console.log(a + b);
}

sum(10, 20);
sum(10, -5);
sum(10, 30.5);
sum(0, 0);
30
5
40.5
0

Live Example

Simple! Wasn't it?

Usually when setting up functions, it's desired to get the function to return back the result of the computation instead of displaying it in some medium such as the HTML document.

In this way, we could do numerous things with the function. For instance, we could pass it to document.write() or console.log() to display the result in the respective location, or assign it to a variable, or even pass it onto some other function as an argument.

The possibilities are endless!

This is accomplished using the return keyword.

The return keyword returns a value from a function when it is called.

The expression to be returned is mentioned after the return keyword inside the function's body.

Here's the syntax for return:

function functionName(parameterList) {
    // some code
    return expression;
}

Let's consider an example.

We'll redefine the sum() function we created above by replacing the logic to output the sum of a and b with the logic to return it.

function sum(a, b) {
    return a + b;
}

Now instead of outputting the sum, the function returns it back.

Here's how to use its return value:

sum(10, 20)
30
sum(10, 20) + 50
80
sum(10, -11) * 10
-10
console.log(sum(10, 20))
30
undefined
sum(10, 10) * sum(5, 5)
200

As apparent in this code, the return value merely replaces the function's invocation expression. We could use the invocation expression just as we would've used the return value normally.

We'll learn much much more about functions in the JavaScript Functions unit.

Objects

Nearly every value that we'll encounter in JavaScript will be an object. Arrays, as we saw above, are objects. Functions are also objects.

In this section we are concerned with the actual object data type in JavaScript that denotes the simplest of all objects.

Here's how to create a plain object literally:

{name1: value1, name2: value2, ..., nameN: valueN}

We start by writing a pair of curly braces ({}). When used to create an object, {} are referred to as object literals. An object created using these is referred to as having been created using the object literal syntax.

Inside these braces, we put individual name-value pairs for the object separated using commas (,). Within each name-value pair, the property name comes first and is separated from the value using a colon character (:).

More readably, this syntax code could be represented as follows:

{
    name1: value1,
    name2: value2,
    ...,
    nameN: valueN
}

Let's consider an example.

We'll create an object with two properties x and y holding the values 10 and 20, respectively:

var obj = {x: 10, y: 20};

Here, obj is an object.

But wait... Technically, both arrays and functions, and many other values, are objects in JavaScript as well. So what's the distinction between a plain object and these other objects?

Well, what we've created here is called a plain object, specifically. A plain object, as the name suggests itself, is an object as well. But it's the simplest of all objects in JavaScript.

An 'object' is a generic term used to refer to any value that is not a primitive. A plain object is a more specific term that refers to the simplest of objects in JavaScript.

Plain objects are handy when we want to store multiple pieces of information under one name.

A good example would be to model a URL using a plain object. Each characteristic of the URL would go as a property in the object, such as its protocol, domain name, path and so on.

Consider the following code where we model the URL https://www.codeguage.com/ using a plain object called url:

var url = {
    protocol: 'https',
    domain: 'www.codeguage.com',
    path: '/'
};

The object has three properties:

  1. protocol — specifies the protocol of the URL, that is whether it is served over http or https.
  2. domain specifies the domain name of the URL.
  3. path specifies the path after the domain name.

Let's now access these.

We could access a property of an object using either of two ways: bracket notation or dot notation.

In the former i.e bracket notation, we write the name of the property as a string within a pair of brackets ([]) following the object value. In the latter, we write the name of the property after a period character (.) following the object value.

Below we access the protocol property on our url object in both these ways:

url.protocol
'https'
url['protocol']
'https'

As you might know, ther are some characteristics of a URL that we have left out in this model. These include its query string and hash. Let's add these to our url object.

We could add a new property to an exisiting object using either of the same two options mentioned before to access a property i.e. bracket notation or dot notation. The only addition required here is that we assign a value to the property using the equals sign (=), just as we do for variables.

Consider the following code:

var url = {
    protocol: 'https',
    domain: 'www.codeguage.com',
    path: '/'
};

// add two new properties
url.queryString = null;
url['hash'] = null;

Here we add two properties to url after it has been created and stored in memory using both the given notations.

Since the URL being modeled (i.e. https://www.codeguage.com/) doesn't have a query string or hash in it, we set the respective properties queryString and hash to null.

Let's check the values of these newly added properties:

url.queryString
null
url.hash
null

Perfect! Just as we wrote them.

Apart from these simple properties, an object could also have methods on it. Methods are special cases of properties.

A method is a property of an object that has a function as its value.

Creating methods is nothing special. We create them just like we create properties on objects. After all, methods are also properties!

The only difference between the two is that instead of assigning a string, number, Boolean, or any other value to a method, we assign it a function. This makes the property callable, and consequently, a method.

Let's define a method on the url object we created above. We'll call it getURL. This method will return back the complete URL formed by concatenating the properties given in the url object:

var url = {
    protocol: 'https',
    domain: 'www.codeguage.com',
    path: '/',

    // return the full URL, as a string
    getURL: function() {
        return url.protocol + '://' + url.domain + url.path;
    }
};

With the method in place, let's now call it:

url.getURL()
'https://www.codeguage.com/'

Since a method is technically a function, we call it using the same syntax employed while calling a function i.e. a pair of parentheses (()) at the end of the expression.

As with simple object properties, we could call the getURL() method using bracket notation as well:

url['getURL']()
'https://www.codeguage.com/'

And this is it for objects!

We'll dive into the complex world of objects and object-oriented programming (shortened as OOP) in the JavaScript Objects unit, where we will learn tons and tons of concepts related to objects.

The typeof operator

Uptil now, we've only been creating variables of given data types without discovering any way to programatically retrieve the type of those variables.

Now we shall address this very idea and understand the typeof operator.

The typeof operator returns the data type of a given expression, as a string value.

The expression comes after the operator as shown below:

typeof expression

Following we test it on different values to see what it returns in each case:

typeof 10; // 'number'
typeof 3.142; // 'number'

typeof "Hello"; // 'string'
typeof 'Hello'; // 'string'

typeof true; // 'boolean'

typeof undefined; // 'undefined'

As you can clearly see here, for all the first four primitive types, typeof returns exactly the same names as of the primitive data types in JavaScript.

We have 'number' for numbers, 'string' for strings, 'boolean' for booleans and "undefined" for undefined.

Now you might be wondering that we forgot to mention null.

Well, we didn't!

When used to inspect a null value, typeof returns an unexpected result that requires a separate discussion on it.

Let's witness the surprise of inspecting null using typeof:

typeof null; // 'object'

Contrary to the expectation that typeof null would return 'null', we get 'object' returned.

This statement has proven to be one of the most confusing aspects of JavaScript for newbie developers.

How is null an 'object'?

What, null is an object? How come?

Well, typeof returning 'object' on the null value is an official bug in JavaScript introduced by its previous implementations.

Unfortunately, it can't be rectified because probably many programs have already utilised this behaviour in their programs - likewise it's present to date simply for backwards compatibility.

Nonetheless one could try to make some intuition by thinking that null represents an empty pointer, and when we talk about pointers we know we are dealing with objects.

If this makes sense or not, that's upto your reasoning about it; it's regardless an inherited bug in JavaScript from previous implementations and doesn't need to make sense, if at all!

Moving on, let's now dive into exploring typeof as used on object data types.

Surprises don't just end at null's typeof behaviour - the operator also returns some unexpected results when used on arrays.

Following is an illustration:

typeof [1, 2, 3]; // 'object'

For array objects, typeof simply returns 'object'; and NOT the much expected value "array".

Fortunately, unlike 'object' for null values, this has got some sense to it and is definitely not another bug!

How is an array an 'object'?

As we know, arrays fall in the object category of JavaScript data types i.e they are stored by references and NOT by their actual values.

JavaScript simplifies the work of typeof by returning 'object' whenever the given expression is a reference to some data in memory.

An array is indeed a reference to an ordered bunch of data in memory and likewise translates to 'object' when inspected by the typeof operator.

This makes perfect sense — everything in the language, except for the primitive types, is an object and hence should return 'object' when inspected by typeof.

The only exception to this is the function data type, where typeof returns "function". We'll see more details below.

But now you might be thinking that how can we figure out whether a given value is an array or not?

Well, JavaScript surely has methods available to solve this problem of detecting pure arrays and they will be discussed, in detail, in the JavaScript Arrays Basics chapter.

Extending to this discussion, if we have pure objects then, as we expect and have already detailed above, typeof will return 'object' once again.

typeof {}; // 'object'
typeof {x: 10}; // 'object'

To end the discussion let's finally see what happens when we are working with functions.

The type returned by typeof for functional values is "function", as can be seen in the following example:

typeof function() {}; // "function"

OK, so now we've another thing to deal with! Functions are an exception case to reference types when evaluated by typeof.

How is a function not an 'object'?

The reason why typeof returns 'function' when used to inspect a function is described as follows:

It's fairly easy to check for a functional value as compared to any other reference type — only an internal property [[Call]] needs to be searched for on the given value and if it exists, we know that we are dealing with a function.

Even if someone was to argue that it isn't difficult to check for arrays as well, just like it isn't difficult to check for functions; there still is a good reason to return 'function' for functions.

The whole idea is that functions are special kinds of objects in JavaScript - they are callable objects.

Because of this distinction from all other objects, it makes a lot of sense to treat them a bit differently — special from all others!

To sum it all up,

  1. For every primitive, except for null, typeof returns a distinctive string.
  2. For every object, except for a function, typeof returns 'object'.
  3. For null, typeof returns 'object'.
  4. For a function, typeof returns 'function'.

Javascript is loosely typed

If you've ever done programming before in languages like Java, C++ etc, you would've surely noticed one difference in variable typing in those languages and JavaScript.

Consider the following code snippet from a Java program:

public class Example {
    public static void main(String args[]) {
        // declare num as an integer
        int num = 10;

        // change num to a Boolean value
        num = true; // throws an error
    }
}

This code would throw an error since the variable num, that is initialised to be an integer, is being changed to a Boolean. Since Java is a strictly-typed language it doesn't allow assigning a value to a variable that doesn't match with its data type.

The same is NOT the case with JavaScript.

In Javascript, we can easily change the data type of a variable after it has been assigned a value, and the interpreter won't throw an error.

This behaviour of the language is why it is termed as being loosely typed.

In contrast to a strictly-typed language, a loosely-typed language allows variables to change their data types, without raising errors.

Consider the code below:

// x is a number
var x = 10;

// x is now a string
x = "Hello";

// x is now a Boolean
x = false;

First we assign a number value to the variable x, but then afterwards change it to a string and then finally to a Boolean. This is possible only because the language doesn't constrict variables with the data types they have been initialised with.

This also explains the fact as to why there aren't any declaration keywords in JavaScript like int, float, double to declare variables of specific data types - the language doesn't need them and can automatically handle the type changes.