I tipi di dato si dividono in due macrocategorie, i tipi primitivi e tutti gli altri. Per conoscere a quale tipo appartiene il valore di una variabile basta usare l'operatore typeof che ritorna il tipo del valore della variabile che si scrive alla sua destra (a volte scritto anche come typeof(a). I tipi primitivi sono:

undefined

Il tipo di dato undefined rappresenta l'assenza di valore, per esempio quando una variabile è stata dichiarata ma non le è ancora stato assegnato un valore. E' l'unico valore che viene assegnato di default dal sistema.

var a; //dichiarazione senza assegnazione, a vale undefined
var b = undefined; //assegnazione esplicita
var c = {};
var d = c.nome; //la proprietà nome non esiste nell'oggetto c, d vale undefined
function test(param) {
    //se il parametro non viene passato nel momento della chiamata della funzione questo vale undefined
}
var e = test(); //se il ritorno di una funzione non è specificato, questa ritorna undefined

console.log(typeof a); //"undefined"
console.log(typeof b); //"undefined"
console.log(typeof d); //"undefined"
console.log(typeof e); //"undefined"

number

Il tipo di dato number è un numero appartenente all'insieme Z dei numeri interi relativi oppure un numero con la virgola. E' un dato primitivo ma può presentarsi anche come un oggetto. Il numero minimo e massimo che si possono esprimere in JavaScript si trovano stampando le costanti Number.MIN_VALUE  e Number.MAX_VALUE. Esiste poi Infinity, un valore globale che è maggiore di qualunque altro numero, e -Infinity che è minore di qualunque altro. Essi sono il risultato di operazioni che darebbero un risultato maggiore / minore del massimo / minimo numero esprimibile. Infine esiste il valore globale NaN che si ottiene quando si cerca di fare un'operazione matematica non consentita, per esempio convertire la stringa "ciao" in un numero.

var f = 4; 
var g = 7.459021; 
var h = -30;
var i = Number.MAX_VALUE;
var j = -0; //esistono sia 0 che -0!
var k = Infinity;
var l = -Infinity;
var m = NaN;

console.log(typeof f); //"number"
console.log(typeof g); //"number"
console.log(typeof h); //"number"
console.log(typeof i); //"number"
console.log(typeof j); //"number"
console.log(typeof k); //"number"
console.log(typeof l); //"number"
console.log(typeof m); //"number"

string

Il tipo di dato string è uno o una serie di caratteri. Una stringa deve essere sempre delimitata da virgolette, singole o doppie. Può esistere anche una stringa vuota, cioè le virgolette non contengono nessun carattere. Anche in JavaScript è necessario fare l'escape dei caratteri come apostrofi e virgolette che devono essere mantenute all'interno della stringa.

var j = "ciao!";
var k = 'Buongiorno \n Good morning \n Bonjour';
var l = "";
var m = ' ';

console.log(typeof j); //"string"
console.log(typeof k); //"string"
console.log(typeof l); //"string"
console.log(typeof m); //"string"

boolean

Il tipo di dato boolean può assumere solo due valori: true e false.

var n = true; 

console.log(typeof n); //"boolean"

null

Il tipo di dato null rappresenta l'assenza di valore come undefined ma deve essere assegnato esplicitamente. E' un tipo primitivo ma se usiamo l'operatore typeof otteniamo come risultato "object".

var o = null;

console.log(typeof o); //"object"

symbol

Questo tipo di dato è stato aggiunto con es6 e non l'ho mai usato ma è comunque un tipo primitivo.

var p = Symbol("a"); //attenzione, non usare la parola chiave new

console.log(typeof p); //"symbol"

Tutti gli altri tipi di dato vengono definiti non primitivi o oggetti. Ci sono moltissimi tipi di oggetti in JavaScript, ma i più utilizzati sono:

object

Un object è una associazione chiave - valore dove la chiave può essere solo una stringa mentre il valore può essere anche di altro tipo.

var r = {
    nome: "Paolino", 
    cognome: "Paperino",
    auto: 313
}; //object literal

console.log(typeof r); //"object"

array

Un array è una associazione chiave - valore dove la chiave può essere solo numerica mentre il valore può essere anche di altro tipo. Per sapere se una variabile è un arraynon possiamo usare l'operatore typeofperchè questo ritorna "object" anche per gli array

var s = [1, 'ciao', 9.36584, true]; //array literal

console.log(typeof s); //"object"

function

In JavaScript anche le funzioni sono oggetti ma usando l'operatore typeof otteniamo "function" perchè sono un tipo prticolare di oggetti in quanto callable.

var t = function(){
    console.log("ciao");
}; //anche la funzione è un tipo di oggetto

function prova() {
    console.log("ciao");
}; // altro modo di dichiarare una funzione

console.log(typeof t); //"function"

Alcuni oggetti devono essere creati espressamente come istanze di una certa classe utilizzando la parola chiave new, mentre per object e arraypossiamo scrivere direttamente l'oggetto, questo viene detto object literal.

Date

Per rappresentare una data utilizziamo un'istanza della classe Date.

var u = new Date(); //stampa la data ed ora corrente
var v = new Date(1982, 4, 19); //stampa il 19 maggio 1982

console.log(typeof u); //"object"
console.log(typeof v); //"object"

RegExp

Per rappresentare una regular expression (cioè una sequenza di simboli che identifica un insieme di stringhe) usiamo un'istanza della classe RegExp.

var w = new RegExp('^[0-9]+$'); //si può anche scrivere come var w = /^\[0-9]+$/;

console.log(typeof w); //"object"

Con es6 sono stati aggiunti questi nuovi tipi:

Set

Un set è un insieme di valori unici.

var x= new Set(); //i valori ripetuti non verranno inclusi nel Set
x.add(3);
x.add(5);
x.add("ciao");
x.add(3);
x.add(5);
x.add("ciao");
x.add(3);
x.add(5);
x.add("ciao");

console.log(typeof x); //"object"

Map

Un map è un insieme di chiave - valore dove sia la chiave che il valore possono essere di qualsiasi tipo.

var y= new Map();
y.set("stringa", "valore associato alla chiave stringa'");
y.set(5, "valore associato alla chiave numerica");

console.log(typeof y); //"object"

Promise

Una promise rappresenta un'azione che non è ancora stata completata ma che lo sarà in futuro sia con esito positivo che negativo.

var z = new Promise(function(resolve, reject) {
    //logica della funzione
});

console.log(typeof z); //"object"

A volte, anzichè creare un oggetto di una determinata classe, utilizziamo direttamente la classe attraverso i suoi metodi statici, ad esempio:

Math

Usiamo la classe Math quando dobbiamo fare operazioni matematiche.

var aa = Math.max(367, -984);

console.log(typeof aa); //"number"
<!-- no html -->
/* no css */
var a; //dichiarazione senza assegnazione, a vale undefined
var b = undefined; //assegnazione esplicita
var c = {};
var d = c.nome; //la proprietà nome non esiste nell'oggetto c, d vale undefined
function test(param) {
    //se il parametro non viene passato nel momento della chiamata della funzione questo vale undefined
}
var e = test(); //se il ritorno di una funzione non è specificato, questa ritorna undefined

console.log(typeof a); //"undefined"
console.log(typeof b); //"undefined"
console.log(typeof d); //"undefined"
console.log(typeof e); //"undefined"

var f = 4; 
var g = 7.459021; 
var h = -30;
var i = Number.MAX_VALUE;

console.log(typeof f); //"number"
console.log(typeof g); //"number"
console.log(typeof h); //"number"
console.log(typeof i); //"number"

var j = "ciao!";
var k = 'Buongiorno \n Good morning \n Bonjour';
var l = "";
var m = ' ';

console.log(typeof j); //"string"
console.log(typeof k); //"string"
console.log(typeof l); //"string"
console.log(typeof m); //"string"

var n = true; 

console.log(typeof n); //"boolean"

var o = null;

console.log(typeof o); //"object"

var p = Symbol("a"); //attenzione, non usare la parola chiave new

console.log(typeof p); //"symbol"

var r = {
    nome: "Paolino", 
    cognome: "Paperino",
    auto: 313
}; //object literal

console.log(typeof r); //"object"

var s = [1, 'ciao', 9.36584, true]; //array literal

console.log(typeof s); //"object"

var t = function(){
    console.log("ciao");
}; //anche la funzione è un tipo di oggetto
function prova() {
    console.log("ciao");
}; // altro modo di dichiarare una funzione

console.log(typeof t); //"function"

var u = new Date(); //stampa la data ed ora corrente
var v = new Date(1982, 4, 19); //stampa il 19 maggio 1982

console.log(typeof u); //"object"
console.log(typeof v); //"object"

var w = new RegExp('^[0-9]+$'); //si può anche scrivere come var w = /^\[0-9]+$/;

console.log(typeof w); //"object"

var x= new Set(); //i valori ripetuti non verranno inclusi nel Set
x.add(3);
x.add(5);
x.add("ciao");
x.add(3);
x.add(5);
x.add("ciao");
x.add(3);
x.add(5);
x.add("ciao");

console.log(typeof x); //"object"

var y = new Map();
y.set("stringa", "valore associato alla chiave stringa");
y.set(5, "valore associato alla chiave numerica");

console.log(typeof y); //"object"

var z = new Promise(function(resolve, reject) {
    //logica della funzione
});

console.log(typeof z); //"object"

var aa = Math.max(367, -984);

console.log(typeof aa); //"number"

Differenze tra i tipi primitivi e non

I tipi primitivi sono immutabili e vengono comparati per valore, i non primitivi sono mutabili e vengono comparati per riferimento. Si può rendere immutabile un tipo non primitivo utilizzando Object.freeze(obj)

var a = 1; //1 è un number, quindi un tipo primitivo
var b = a;
a = 2; //ora a vale 2 ma b resta invariato, a meno che non assegniamo a b un altro valore esplicitamente questo non può essere cambiato
console.log(a); //2
console.log(b); //1

var c = 3;
var d = 3;
if(c == d) { //stiamo confrontando i valori di c e d
    console.log("c e d sono uguali"); //verrà stampata questa stringa
}
else {
    console.log("c e d sono diversi");
}

var e = { //un oggetto non è un tipo primitivo
    nome: "Paperina"
}
var f = e;
e.nome = "Minnie"; //ora abbiamo cambiato e, anche f cambierà di conseguenza
console.log(e);
console.log(f);

var g = {
    nome: "Pippo"
}
var h = {
    nome: "Pippo"
}
if(g == h) { //stiamo confrontando i puntamenti in memoria di g e h, non i loro valori
    console.log("g e h sono uguali");
}
else {
    console.log("g e h sono diversi"); //verrà stampata questa stringa
}

var i = {
    nome: "Mickey",
    cognome: "Mouse"
}
Object.freeze(i);

i.nome = "Topo"; //nessun effetto
i.lavoro = "Detective"; //nessun effetto

console.log(i); //{nome: "Mickey", cognome: "Mouse"}

var j = {
    nome: "Mickey",
    cognome: "Mouse",
    amici: ["Pippo", "Basettoni"] 
}
Object.freeze(j);

j.amici[1] = "commissario Basettoni"; //ha effetto perchè Object.freeze agisce solo sul primo livello del'oggetto

console.log(j); //{nome: "Mickey", cognome: "Mouse", amici: ["Pippo", "commissario Basettoni"]}

//Attenzione!!
var a = [1, 2];
var b = a;

a = []; //non sto modificando a ma sto riassegnando a
console.log(b); //1, 2
<!-- no html -->
/* no css */
var a = 1; //1 è un number, quindi un tipo primitivo
var b = a;
a = 2; //ora a vale 2 ma b resta invariato, a meno che non assegniamo a b un altro valore esplicitamente questo non può essere cambiato
console.log(a); //2
console.log(b); //1

var c = 3;
var d = 3;
if(c == d) { //stiamo confrontando i valori di c e d
    console.log("c e d sono uguali"); //verrà stampata questa stringa
}
else {
    console.log("c e d sono diversi");
}

var e = { //un oggetto non è un tipo primitivo
    nome: "Paperina"
}
var f = e;
e.nome = "Minnie"; //ora abbiamo cambiato e, anche f cambierà di conseguenza
console.log(e);
console.log(f);

var g = {
    nome: "Pippo"
}
var h = {
    nome: "Pippo"
}
if(g == h) { //stiamo confrontando i puntamenti in memoria di g e h, non i loro valori
    console.log("g e h sono uguali");
}
else {
    console.log("g e h sono diversi"); //verrà stampata questa stringa
}

E' possibile wrappare i tipi primitivi boolean number e string nelle loro controparti oggetto ma non è di nessuna utilità perchè vengono comunque trattati come primitivi.

var a = new Boolean(true);
var b = new String("a");
var c = new Number(3);

console.log(typeof a); //object
console.log(typeof b); //object
console.log(typeof c); //object

console.log(a instanceof Boolean); //true
console.log(b instanceof String); //true
console.log(c instanceof Number); //true

var d = !a;
console.log(typeof d); //boolean
var e = b + "ciao";
console.log(typeof e); //string
var f = c + 5;
console.log(typeof f); //number