Course: JavaScript

Progress (0%)

  1. Foundation

  2. Numbers

  3. Strings

  4. Conditions

  5. Loops

  6. Arrays

  7. Functions

  8. Objects

  9. Exceptions

  10. HTML DOM

  11. CSSOM

  12. Events

  13. Drag and Drop

  14. opt Touch Events

  15. Misc

  16. Project: Analog Clock

JavaScript Data Types

Chapter 8 51 mins

Learning outcomes:

  1. What are data types
  2. What are primitives and objects
  3. Numbers, strings, Booleans, undefined and null
  4. Arrays, functions and plain objects
  5. The typeof operator
  6. Dynamically-typed nature of JavaScript

Introduction

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

In this chapter, we shall get an overview of the data types that JavaScript comes equipped with, out of the box.

We'll understand the distinction between primitive and object types before moving on to explore the six most common primitive types and the three most common object types. Moreover, we'll also consider the typeof operator, used to inpsect the type of a given value.

This foundational understanding of data types in JavaScript is imperative for you as you move on to learn tons and tons of additional concepts of the language. In the coming units, we'll go over each of these types, one-by-one, in even more detail, but first let's get a quick and brief overview of all of them.

What are data types?

Before we go on and explore the different data types available in JavaScript, it's worthwhile to discuss what exactly is meant by a data type.

In simple terms,

A data type describes a set of values and the operations possible on those values.

Let's take an example to make intuition of this basic definition.

Consider the integer type — a very common data type in programming languages of all kinds of levels.

We all know that the possible values of integers in mathematics ranges from negative infinity (::-\infty::) all the way to positive infinity (::+\infty::), whereby each value is a whole number (i.e. a number without a fraction). The set could be expressed as ::\dots::, ::-2::, ::-1::, ::0::, ::1::, ::2::, ::\dots::.

However, in the realms of machines, integers are finite. We can only have a limited range of them. Even if the underlying mechanism of storing integers changes so that we can store arbitrarily long integers, as in Python, we are still limited by the total amount of memory available on the machine for the largest possible integer. In short, there is finiteness to integers in computing.

If we say that the integer type, in a programming language, is unsigned and consumes 4 bytes of memory per value, then the range of values possible is 0 to 4294967295.

Apart from these values, the integer type also represents the possible operations that we can carry out on these values. Common operations include addition, subtraction, multiplication, division, exponentiation, and modulo.

To boil it down, a data type is an abstract idea that helps us group data according to its value and the whole set of operations possible on that data.

In some instances, a data type could represent just one single value without any operations possible to be performed on it. In others, it could represent an almost infinite (but obviously limited by the available memory) set of values with a large number of supported operations.

Now that the definition is clear, it's time to explore the idea of primitives and objects in JavaScript.

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 one of the simplest forms of data.

A primitive value could be thought of as an atom, if you're familiar with chemistry from the old days at school. An atom is the simplest form of an element, and that's exactly what a primitive is in JavaScript.

The simplest example of primitive values would be numbers. Consider the value 10. This, as you know, is a number in JavaScript. But most importantly, it's a primitive. It's one of the simplest values that can be represented in JavaScript.

The key characteristic of primitives, as we shall discover later on, is that they don't have any properties/methods attached to them. So when we say that 10 is a primitive value, we, in effect, mean that there are no properties/methods attached to this value 10.

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

For this course, we'll only be concerned with the first five. The remaining two types are covered in our Advanced JavaScript course.

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

An object is a value composed of primitives.

Going with the analogy that a primitive resembles an atom, an object then resembles a molecule. A molecule is made up of atoms and so are objects, which are made up of primitives.

Simply put, if a value isn't a primitive in JavaScript, then it is an object. Apart form the seven primitive data types discussed above, everything else is an object in the language.

An object, unlike a primitive, can have properties/methods attached to it.

An object is sometimes also referred to as a reference. And by that means, the object type is also known as the reference type. That where does the term 'reference' come from, we'll explore later on in this chapter.

Let's now start exploring the different primitive types in JavaScript before considering its 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, artificial intelligence, and what not.

In programming, generally, numbers are categorized 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, or floating-point number, is a number with a decimal point.

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

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 the type '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. We've already seen strings in the previous chapters.

A string is a sequence of textual characters.

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

The following code shows two strings:

var lang = 'JavaScript';
var os = "Windows";

The first string is created using single quotes ('') while the second one is created using double quotes ("").

Recall that there is yet a third way to denote strings and that is using a pair of backticks (``). Such strings are called template literals and could contain JavaScript code within them. We'll learn more about template literals in JavaScript Strings — Basics.

Let's now talk about two vital concepts of strings.

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.

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]
'n'

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.

Apart from the index, another core concept of strings is that of the length. In particular, the total number of characters in a string is referred to as its length.

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

The string lang, shown above, has 10 characters, hence the length 10. Similarly, os has 7 characters, hence the length 7.

But wait a minute. Didn't we say that a string is a primitive and that a primitive doesn't have properties/methods on it?

How come a string has a property?

Well, this is by virtue of JavaScript's behavior behind the scenes. Let's look into it.

How can a primitive in JavaScript have a property on it? Via autoboxing.

To restate it, a primitive can't have a property on it. Ever. However, this doesn't mean that we can't use a primitive in some way such that the final result has a property on it.

JavaScript internally performs what's known as autoboxing when it sees that we are trying to use a property on a primitive.

The idea of autoboxing is not specific to JavaScript; it's done by some other programming languages as well, such as C# and Java.

Essentially, excluding undefined and null, JavaScript defines wrapper classes (sometimes also referred to as wrapper types) for all primitive types, used to denote corresponding objects of those types. The nomenclature of these objects is also pretty intuitive.

Shown below are the five wrapper types corresponding to the five primitives:

  1. Number for numbers
  2. String for strings
  3. Boolean for Booleans
  4. BigInt for big integers
  5. Symbol for symbols

Autoboxing is simply when JavaScript automatically boxes, i.e. wraps, a primitive value into an object based on its corresponding wrapper class.

So, for example, suppose that str is a variable holding a string. Accessing a property on str, like str.length would autobox str into a String object and then access the property on the object before deleting the object.

To help understand this better, consider the following code:

var str = 'Autoboxing';
console.log(str.length);

When the expression str.length in line 2 is encountered, as stated before, autoboxing happens.

Behind the scenes, here's what actually gets executed:

var str = 'Autoboxing';
var strBoxed = new String(str);
console.log(strBoxed.length);
strBoxed = undefined;
  • First, the value str is boxed using its corresponding wrapper type String and stored in a temporary variable called strBoxed. (We'll learn more about the new keyword and the String class later on in this course.)
  • Then, the property length is accessed on this wrapper object strBoxed and then the result logged to the console. Since strBoxed is an object (not a primitive), it makes perfect sense for it to have a property available on it.
  • Finally, this temporary variable is deleted from memory, which could best be shown in JavaScript code by setting the temporary variable to undefined.

Keep in mind that what we've shown above is just for the sake of visualizing autoboxing in JavaScript code. For example, there isn't actually a variable such as strBoxed created to store the wrapper object for the variable str shown above — it's purely created to help you understand autoboxing.

How exactly autoboxing is performed is completely implementation-dependent. But it's definitely a thing in JavaScript, and likewise, worth knowing.

So was understanding autoboxing easy?

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 of 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'll 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.

An array is like a sequence of values or a list of items. It has the capability of storing multiple values under one hood. The individual values of an array are formally called elements, or items, of the array.

Each element sits at a given position, formally known as its index in the array. The total number of element is referred to as the array's length.

Strings and arrays are both sequences of data. Hence the same concepts of indexes and length apply to both of them.

Array elements can be of any data type. They could be numbers, 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, contain numbers and strings.

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 (,). Such an array, denoted directly using [], is called an array literal.

There is another way of creating an array and that is using the Array() constructor. We'll see it in action in the JavaScript Arrays unit.

In the following code, we create an array literally and store it in a variable nums:

var nums = [1, 5, 10];

This array is comprised of three elements: 1, 5 and 10.

Accessing a given element from an array has the same syntax of accessing a character from a string.

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

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

nums[0]
1
nums[2]
10

Accessing an out-of-range index yields undefined:

nums[3]
undefined
nums[-1]
undefined

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 inspecting the length of our nums array:

nums.length
3

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

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().

By default, sort() sorts the elements of an array alphabetically. In particular (by default) it converts each element into a string, and then performs the comparisons between the resulting string values to determine which one should come first, which one should 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; not a new one created.

Consider the following code:

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

langs.sort();

console.log(langs);

First, we define a variable langs and initialize it with an array. 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:

var nums = [100, 9, 80, 2, 0, -1, -50]
undefined
nums.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 an argument to sort(). That how exactly does this argument function work, and why exactly do we need it will be explored, in detail, in the chapter JavaScript Arrays — Sorting.

For now, we could, however, better understand what a function is and how it works.

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.

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

Let's see what a function is.

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

A function is used to group together some code that could be executed later on at will. This execution is initiated by calling — or better to say, invoking — the function.

In JavaScript, functions could be named or anonymous. For now, we are concerned with the former, i.e. named functions.

The function keyword is used to create a function in JavaScript.

Shown below is the syntax of creating a named function:

function functionName(parameterList) {
   statements
}

We start with the function keyword, followed by the name functionName of the function (recall that functionName is a placeholder that you ought to fill with actual text). This name has to abide by the variable naming rules of JavaScript that we saw in JavaScript Variables — Rules for naming variables.

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 pair of curly braces ({}) denoting the function's body. The body consists of statements that are executed when the function is invoked.

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

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, the function. Without the parentheses, we'd be simply referring to the function's definition.

Alright, with a lot of theory been discussed, it's finally time for some examples.

In the code below, we create a function named 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() (which is yet another function!) and then output the greeting message via document.write() with the input name included.

Let's now call this function:

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

sayHello();

Live Example

The last statement here calls sayHello by virtue of the parentheses following it, i.e. sayHello(). This, in effect, executes the code defined inside sayHello.

Quite simple, wasn't it?

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 we call the function.

Such additional pieces of data are called arguments, or sometimes as 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 that actual value.

You'll see the terms 'arguments' and 'parameters' used interchangeably out there. Although, this is not completely wrong, it's still good to know of the distinction between both these ideas.

Let's consider another example.

Following we define a function sum() to compute the sum of two numbers:

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

As can be seen, the function has two parameters a and b that get added and the result, ultimately, logged to the console.

Let's now 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 a function to return back the result of the computation instead of displaying it on some medium such as the HTML document.

In this way, we could reuse the function in numerous contexts. 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 on to some other function as an argument.

The possibilities are endless!

This return keyword is used to return a value from a function.

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

The expression to be returned is mentioned right after the return keyword, which itself comes inside the function's body.

Here's the syntax for return:

function functionName(parameterList) {
   statements
   return expression;
}

Let's consider an example.

We'll redefine the sum() function that we created above to simply return the sum of a and b, instead of logging it:

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

Let's now make a couple of calls of this function from within the console.

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 is apparent here, the return value of sum() merely replaces the function's invocation expression and is being used just like a normal number.

There is a lot more to the beautiful and powerful world of functions in JavaScript. We'll learn more about them in the JavaScript Functions unit.

Objects

A large part of our time coding in JavaScript will be devoted to working with objects.

Objects are the cornerstone of JavaScript. JavaScript, as we shall explore in more detail in the JavaScript Objects unit, is an OOP (Object-Oriented Programming) language by design. This simply means that it's built around the idea of objects.

But what is an object?

An object is a set of properties and methods.

Properties define the characteristics of an object while methods define its behavior, its actions.

Objects in JavaScript, and other programming languages, work pretty much the same way as objects in the real world. Let's understand this with the help of a real-world object.

Think of real-world objects

Take, for example, a toaster oven. It's an object used in everyday life, used for simple baking concerns like baking a scrumptious pound cake or maybe even some delicious cookies.

What characteristics can you think of a toaster oven?

Well, it could have a model number, a warranty period, a body color, a temperature grading, a size, an electrical power rating, and so on. These are the properties of the oven.

Similarly, what behavior, or actions, can you think of a toaster oven?

Well, we could switch the oven on or off, heat the top or the bottom element, turn on the fan, set up a timer, and so on. These are the methods of the oven.

There are many different kinds of objects in JavaScript. Arrays, as we saw above, are objects. Functions are objects too.

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

Here's the syntax of an object literal:

{key1: value1, key2: value2, ..., keyN: valueN}

We start by writing a pair of curly braces ({}). Inside these braces, we put individual key-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:

{
   key1: value1,
   key2: value2,
   ...,
   keyN: 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 utilized this behavior 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 behavior - 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 string containing the name of its type.
  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 dynamically-typed

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

Consider the following code snippet from a Java program:

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

      // Change num to a Boolean value
      num = true; // Throws an error
   }
}

You're obviously not required to understand what's going on here; just the fact that we define a variable num as an integer (int) in line 4 and then later on change its value to a Boolean in line 7.

As soon as the Java parser comes to line 7, it throws an error. This is because the variable num is declared to be an integer, however, it gets assigned a Boolean value, which is invalid.

This behavior of Java directly stems from the fact that it is a statically-typed language.

The types of all variables in the language are declared upfront while writing the code, and then it's not possible to change the values of those variables to any other type. The types of variables remain static throughout the course of the program, hence the name 'statically-typed.'

JavaScript does NOT work this way. Instead JavaScript is a dynamically-typed language.

In JavaScript, we don't have to (and in fact, even can't) declare the types of variables upfront. During the course of a program, we can easily change the types of values stored in a variable, and the interpreter won't complaint even for a second.

The code below illustrates this:

// x is a number
var x = 10;

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

// x is now a Boolean
x = false;

First, we initialize the variable x with a number, 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 a given data type.

This also explains the fact as to why there aren't any type declaration keywords in JavaScript such as int, float, double, to declare variables of specific data types. The language just doesn't need them — it manages the entire type system and the complexity associated with it itself.

Isn't this remarkable?