Data types

What are data types?

Let's take a closer look at values. We already know that values are assigned to variables or constants and that operands can be values. There are different types of values, like strings, numbers, booleans or objects: values are of a certain data type.

The typeof operator can be used to return a string indicating the data type of its operand: typeof operand or typeof (operand).


let varA = 'John';
let varB = false;	
let varC = 1/3;

let typeOfVarA = typeof (varA);
console.log(typeOfVarA); // logs: "string"
console.log(typeof varB); // logs: "boolean"
console.log(typeof varC); // logs: "number"

Some strange JavaScript logic: accessing an undeclared variable trows a ReferenceError, except when via a typeof operand. Then it returns "undefined" (note: not the value undefined but the string "undefined").


console.log(typeof someUndeclaredVar); // logs: "undefined"
console.log(someUndeclaredVar); // logs: ReferenceError: someUndeclaredVar is not defined.

All programming languages make use of data structures, but not all in the same way. JavaScript is a dynamically typed and loosely typed programming language. The values have data types, not the variables, constants or properties. In JavaScript any variable can be (re)assigned values of all types.


let myVar;

myVar = "Hello World!"; // value is of data type "string"
console.log(typeof myVar); // logs: "string"

myVar = Math.PI; // Reassigning different value of different type
console.log(typeof myVar); // logs: "number"	

In other programming languages variables may be designated (at declaration) to one particular data type, like in Java.


// Code in Java:
public class MyMainClass {
  public static void main(String[] args) {
    String myVar = "Hello World!"; // declaring a string variable
    myVar = 20; // error: incompatible types.
  }
}	

In JavaScript values are either of primitive data types or of the object data type. Primitives are values of the types: string, number, boolean, undefined, null, BigInt or symbol. All other values are of type object. Later this tutorial much more about primitives and objects.

Literals

Values get to be of a specific data type in multiple possible ways, as will be covered in the next chapters. Generally the notation of a value needs to be in a specific format corresponding to the data type. Such representations of values are called literals. A literal at assignment automatically makes that value of the corresponding data type. In the example below myVar gets assigned an object via an object literal: two curly brackets enclosing two property names that both get assigned a string ('Jane' and 'Doe'). The strings are represented as string literals: they are in quotation marks.


let myVar;

myVar = { firstName:'Jane', lastName:'Doe' }; // value is of data type "object"
console.log(typeof myVar); // logs: "object"
console.log(typeof myVar.firstName); // logs: "string" // type of object property

myVar = 313; // Reassigning different value of different type, using a number literal
console.log(typeof myVar); // logs: "number"

Note that statements enclosed in curly brackets constitute a block statement. However, if JS expects a value (as in the above example) it treats the curly brackets, and what is inside, as an object literal, and not as a block statement.

Numeric literals, string literals and object literals are covered in more detail in the next chapters.

Literals of primitives null and boolean are merely keywords expressing a certain state of the primitive value: the keyword null as the only literal for the primitive null and the keywords true and false as the only two literals for the primitive boolean. In JS undefined is technically not a literal, but a property of the global object (later more about this).


let myVar;

myVar = true; // boolean literal: value is of data type "boolean"
console.log(typeof myVar); // logs: "boolean"

myVar = undefined; // technically not an undefined literal. Value is of data type "undefined"
console.log(typeof myVar); // logs: "undefined"

myVar = null; // null literal: value is of data type "null"
console.log(typeof myVar); // logs: "object" // This is generally considered a legacy mistake in JS.

Primitive data types

Primitive values or simply primitives are values of one of the following data types:

boolean

Logical values true and false are the only two values of the boolean data type.

undefined
The value undefined is the only value of data type undefined.
null

Value null is the only value of data type null.

(PS, typeof null; returns "object", which is generally considered a legacy mistake in JS.)

string
String type values are sequences of text, such as "Hello world!" and "" (empty string).
number

Integers (-123, -10, 0, 1235, 2.1e4) and decimal fractions (-512.022, 3.1415, 1e-3) are of the number type. Also NaN ("Not a Number") and Infinity are values of the number type. All values of this data type are stored as double precision floating point numbers.

(Note that NaN (typeof NaN;) is of the data type number. So, "Not a Number" is a number...)

BigInt
BigInt is an integer data type, especially for representing large integers, greater than 253 - 1. Literals for integers of this type are constructed by appending n to the end of the integer (-123n, -10n, 0n, 1235n). See Floating points in JavaScript for more information on when BigInts can be useful.
symbol
Represents a unique identifier. Later more about symbols.

Be aware that data types are not generally defined. Different programming languages use data types in different ways. JavaScript only has two numeric data types ("number" and "BigInt"), but Java, for instance, has numeric data types "byte", "short", "int", "long", "float" and "double". And in Java, data type "String" is not a primitive, but an object.

Undefined vs. null

A variable is automatically assigned the value undefined at declaration and before explicit initialization. Accessing non-existent object properties returns value undefined (accessing a non-existent object method throws a TypeError). Also accessing a parameter in a function when the function is called without providing an argument for this parameter returns value undefined.

Explicitly assigning value undefined is possible, but it is more common to use null for explicit assignment of an "empty value".


let someVar;
console.log(someVar); // logs: undefined	

let someObj = {}
console.log(someObj.someProperty); // logs: undefined

let someArray = []
console.log(someArray[0]); // logs: undefined

function someFunc(someParameter) { console.log(someParameter); }
someFunc(); // logs: undefined

let foobar = undefined;
console.log(foobar); // logs: undefined

Value null needs to be explicitly assigned. JS never automatically assigns value null. Value null is assigned to represent the absence of any value.


let someVar = 313;
someVar = null;	// "reset" someVar
console.log(someVar); // logs: null

When converted to a number, value null converts to 0, and undefined converts to NaN ("Not a Number"). Values null and undefined both convert to false in a Boolean context (except in comparison operations). Values false, 0, null, undefined and NaN (and an empty string) are called falsy values. Values null and undefined are called nullish values. In chapters Type coercion, Falsy & truthy and Nullish this all will be explained in more detail.


// Next a constructor function (Number()) is used to convert 'null' and 'undefined' into a number.
// Constructor functions will be explained in more detail in a later chapter.
console.log( Number(null) ); // logs: 0
console.log( Number(undefined) ); // logs: NaN

console.log(null == undefined); // logs: true
if (!null) { console.log("this gets returned, because 'not null' converts to 'not false', which is true"); }

Object data type

JavaScript has a number of special standard built-in objects, like the object array. A function in JavaScript is also an object, although the typeof operator returns "function". Standard built-in objects are sometimes referred to as "global objects", not to be confused with the global object (later more about this).


// Object data types:

let myObject = { firstName:'Jane', lastName:'Doe' },
    myArray = ["green", "red", "blue"],
    myFunction = function() { console.log("Hello World!") };

console.log(typeof myObject); // logs "object"
console.log(typeof myArray); // logs "object"	
console.log(typeof myFunction); // logs "function"		

In object-oriented programming (OOP) an object represents "something" that has properties and can perform actions, so called methods. For instance, a robot gripper may have properties like maximum and minimum reach or the number of degrees of freedom and methods like "open gripper", "close gripper", "rotate gripper". In JS an object can be defined as shown in the next example (working web application here). Later much more about objects in JavaScript.


// Define object "pen":
const pen = {
  // properties:
  color: 'black',
  lineWidth: 1,
  beginX: 0,
  beginY: 0,
  endX: 100,
  endY: 100,
  // method:
  drawLine: function() {
    ctx.beginPath();
    ctx.lineWidth = this.lineWidth;
    ctx.strokeStyle = this.color;			
    ctx.moveTo(this.beginX,this.beginY);
    ctx.lineTo(this.endX,this.endY);
    ctx.stroke();		
  }
}

// Drawing a red line from (0,0) to (300,200):	
pen.color = 'red'; // change property "color" of object "pen".
pen.endX = 300; // change property "endX" of object "pen".
pen.endY = 200; // change property "endY" of object "pen".
pen.drawLine(); // invoke method "drawLine" of object "pen".  

Value data types and reference data types

For the sake of convenience, we will use "variable" where we mean "variable, constant or object property" in the rest of this section.

As mentioned earlier, in JavaScript values are either of primitive data types or of the object data type. In JavaScript, one of the differences between the two is determined by how a value is stored in memory. From this perspective we distinguish value data types and reference data types.

Primitives are of the so called value data type. When a primitive value is assigned to a variable, the value is stored in the variable, which can be thought of as a memory address location identified by the name of the variable. Each variable takes its own memory location, holding a value. Reassigning a primitive value to the variable simply overwrites the old value with the new value in the memory location. It is not possible for different variables to reference the same primitive value.

Objects are of the so called reference data type. Object values are not stored in the variable. Object values are stored in a different kind of memory location (heap vs stack memory). Instead of a value, now a pointer or reference is stored in the variable. That reference "points" to the object value stored in the separate memory location. Multiple variables can hold a reference to the same object value.

Primitive values are immutable: they cannot be changed, only be overwritten (by reassignment). Object values are mutable: unlike primitives, they can be changed.


const objectVar = { a: 2 };
objectVar.b = 3;
console.log(objectVar); // logs: { a: 2, b: 3 } // object has been changed, no reassignment.

const primitiveVar = "hello";
primitiveVar = "hi"; // TypeError: invalid assignment to const 'primitiveVar'

In JavaScript primitives comparison and assignment are value based, objects comparison (equality) and assignment are reference based.


// *** value based: ***
const privateVar1 = 2;
const privateVar2 = 2;

// both variables have an equal value:
console.log(privateVar1 === privateVar2); // logs: true

// *** reference based: ***
const objectVar1 = { a: 2 };
const objectVar2 = { a: 2 };

// both variables reference different objects: 
console.log(objectVar1 === objectVar2); // logs: false
console.log({ a: 2 } === { a: 2 }); // logs: false
console.log(objectVar1.a === objectVar2.a); // logs: true // value based

Copying a variable holding a primitive simply creates a new variable holding a new equal primitive value. Copying an object however, creates a new variable holding a new equal pointer, pointing to the same object value! Only a comparison for equality of two references to the same object returns true.


const objectVar = { a: 2 };
const objectVarCopy = objectVar;

// Two variables, one single object,
// both objects are pointing to same object:
console.log(objectVar === objectVarCopy); // logs: true

// Changing the object changes it for both variables: 
objectVar.a = 20;
console.log(objectVarCopy.a); // logs: 20