Classi
Le classi sono fondamentali per costruire strutture dati. Un’analogia utile è pensare a una classe come a uno stampino per biscotti (cookie cutter): definisce la forma, mentre le istanze sono i biscotti creati.
Creare una classe
Quando crei una classe, il nome va sempre capitalizzato. Ogni classe ha un constructor, che crea le nuove istanze:
class Cookie { constructor(color) { this.color = color }}Il costruttore riceve i parametri (in questo caso color) e li assegna all’istanza usando this. this si riferisce all’istanza specifica che stiamo creando.
Creare istanze
Per creare nuove istanze, usiamo la parola chiave new:
let cookie1 = new Cookie('green')let cookie2 = new Cookie('blue')cookie1 è un’istanza specifica di Cookie con colore verde. cookie2 è un’altra istanza con colore blu. Il this nel costruttore si riferisce all’istanza specifica che viene creata.
Getters e setters
Le classi hanno due categorie principali di metodi: getters (per leggere) e setters (per modificare):
class Cookie { constructor(color) { this.color = color }
getColor() { return this.color }
setColor(color) { this.color = color }}Esempio d’uso:
let cookie1 = new Cookie('green')cookie1.getColor() // 'green'
cookie1.setColor('yellow')cookie1.getColor() // 'yellow'Classi per strutture dati
Tutte le strutture dati che costruiremo useranno classi. Ad esempio, una linked list avrebbe questa struttura:
class LinkedList { constructor(value) { // Crea il primo nodo della linked list }
push(value) { // Aggiunge un elemento alla fine }
unshift(value) { // Aggiunge un elemento all'inizio }
insert(index, value) { // Inserisce un elemento a un indice specifico }
remove(index) { // Rimuove un elemento a un indice specifico }
pop() { // Rimuove l'ultimo elemento }
shift() { // Rimuove il primo elemento }}Uso della classe:
let myLinkedList = new LinkedList(23)myLinkedList.push(7)myLinkedList.unshift(3)myLinkedList.insert(1, 11)myLinkedList.remove(1)myLinkedList.pop()myLinkedList.shift()Le classi ci permettono di creare strutture dati con metodi specifici per manipolare i dati in modo organizzato e riutilizzabile.
Puntatori
I puntatori sono fondamentali per capire come funzionano gli oggetti in JavaScript. Il comportamento è diverso tra valori primitivi e oggetti.
Valori primitivi (senza puntatori)
Con valori primitivi come numeri, quando assegniamo una variabile a un’altra, copiamo il valore:
let num1 = 5let num2 = num1
num1 = 10console.log(num1) // 10console.log(num2) // 5 (non è cambiato)Quando impostiamo num2 = num1, stiamo solo copiando il valore 5 al momento della dichiarazione. Se poi cambiamo num1, num2 non viene influenzato perché non c’è un collegamento permanente.
Oggetti (con puntatori)
Con gli oggetti, quando assegniamo una variabile a un oggetto, stiamo creando un puntatore all’oggetto in memoria:
let obj1 = { value: 11 }let obj2 = obj1Quando facciamo obj2 = obj1, non stiamo creando un nuovo oggetto con gli stessi valori. Stiamo dicendo a obj2 di puntare allo stesso oggetto in memoria a cui punta obj1.
let obj1 = { value: 11 }let obj2 = obj1
obj1.value = 22console.log(obj1) // { value: 22 }console.log(obj2) // { value: 22 } (anche questo è cambiato!)Entrambi gli oggetti mostrano value: 22 perché puntano allo stesso oggetto in memoria. Modificare uno significa modificare l’altro.
Spostare i puntatori
I puntatori possono essere spostati per puntare a oggetti diversi:
let obj1 = { value: 11 }let obj2 = obj1let obj3 = { value: 33 }
obj2 = obj3 // obj2 ora punta a obj3obj1 = obj3 // obj1 ora punta a obj3Ora obj1 e obj2 puntano entrambi a obj3, mentre l’oggetto originale { value: 11 } non ha più puntatori che lo referenziano.
Garbage collection
Se un oggetto non ha più variabili che lo referenziano, non possiamo più accedervi. JavaScript periodicamente rimuove questi oggetti inutilizzati attraverso un processo chiamato garbage collection, liberando memoria.
Questo è importante quando lavoriamo con strutture dati: dobbiamo assicurarci di non perdere i riferimenti agli oggetti che vogliamo mantenere, altrimenti verranno rimossi dalla memoria.