Impara a lavorare con gli oggetti, le proprietà, i metodi e le operazioni fondamentali.
Cos'è un Oggetto in JavaScript?
Un oggetto è una collezione di proprietà, dove ogni proprietà è una coppia chiave-valore. Gli oggetti sono fondamentali per organizzare dati complessi e rappresentare entità del mondo reale.
Oggetti nel Mondo Reale
Pensa a un oggetto come a una scheda descrittiva: una persona ha nome, cognome, età, indirizzo. Un libro ha titolo, autore, anno, pagine. Gli oggetti JavaScript ti permettono di raggruppare queste informazioni correlate!
🎯 Array vs Oggetti
Array
- Lista ordinata
- Accesso per indice numerico
- Elementi omogenei (tipicamente)
["Mario", "Anna", "Luca"]
Oggetti
- Collezione proprietà
- Accesso per chiave (nome)
- Dati strutturati
{nome: "Mario", età: 30}
Creazione Oggetti
- Object Literal (Consigliato)
Il modo più comune e leggibile per creare oggetti.
Creazione con {}
// Oggetto vuoto
let oggetto = {};
// Oggetto con proprietà
let persona = {
nome: "Mario",
cognome: "Rossi",
età: 30,
professione: "Sviluppatore"
};
// Oggetto complesso con proprietà di vari tipi
let prodotto = {
id: 1001,
nome: "Laptop",
prezzo: 999.99,
disponibile: true,
categorie: ["elettronica", "computer"],
specifiche: {
cpu: "Intel i7",
ram: "16GB",
storage: "512GB SSD"
}
};
console.log(persona); // {nome: "Mario", cognome: "Rossi", età: 30, ...}
- new Object() (Meno Usato)
Costruttore esplicito, ma meno leggibile.
Creazione con new Object()
let persona = new Object();
persona.nome = "Mario";
persona.età = 30;
console.log(persona); // {nome: "Mario", età: 30}
// ✅ Meglio usare object literal
let personaMigliore = {
nome: "Mario",
età: 30
};
- Object.create() (Avanzato)
Crea oggetto con prototipo specifico.
Object.create()
// Oggetto prototipo
let personaBase = {
saluta: function() {
return `Ciao, sono ${this.nome}`;
}
};
// Crea oggetto che eredita da personaBase
let mario = Object.create(personaBase);
mario.nome = "Mario";
console.log(mario.saluta()); // "Ciao, sono Mario"
💡 Proprietà Speciali
Le chiavi delle proprietà possono contenere spazi o caratteri speciali, ma vanno racchiuse tra apici.
let oggetto = {
nome: "Mario", // Chiave normale
"data di nascita": "1994-03-15", // Chiave con spazi
"user-id": 12345, // Chiave con trattino
123: "numero come chiave" // Chiave numerica (convertita a stringa)
};
console.log(oggetto.nome); // "Mario"
console.log(oggetto["data di nascita"]); // "1994-03-15"
console.log(oggetto["user-id"]); // 12345
console.log(oggetto[123]); // "numero come chiave"
Accesso alle Proprietà
- Dot Notation (Notazione Punto)
Il modo più comune e leggibile.
Accesso con .
let persona = {
nome: "Mario",
cognome: "Rossi",
età: 30,
indirizzo: {
via: "Via Roma 1",
città: "Milano",
cap: "20100"
}
};
// Accesso semplice
console.log(persona.nome); // "Mario"
console.log(persona.cognome); // "Rossi"
// Accesso a oggetti annidati
console.log(persona.indirizzo.città); // "Milano"
console.log(persona.indirizzo.via); // "Via Roma 1"
// Proprietà inesistente
console.log(persona.telefono); // undefined
- Bracket Notation (Notazione Parentesi Quadre)
Più flessibile, permette chiavi dinamiche e con spazi.
Accesso con []
let persona = {
nome: "Mario",
cognome: "Rossi",
"data di nascita": "1994-03-15"
};
// Accesso base
console.log(persona["nome"]); // "Mario"
console.log(persona["cognome"]); // "Rossi"
// Chiavi con spazi (SOLO con bracket notation)
console.log(persona["data di nascita"]); // "1994-03-15"
// Chiavi dinamiche
let prop = "nome";
console.log(persona[prop]); // "Mario"
// Chiavi calcolate
let chiave = "co" + "gnome";
console.log(persona[chiave]); // "Rossi"
📊 Dot vs Bracket Notation
| Caratteristica | Dot Notation | Bracket Notation |
|---|---|---|
| Sintassi | obj.prop |
obj["prop"] |
| Leggibilità | ⭐⭐⭐ Alta | ⭐⭐ Media |
| Chiavi con spazi | ❌ No | ✅ Sì |
| Chiavi dinamiche | ❌ No | ✅ Sì |
| Quando usare | Default (80% casi) | Chiavi dinamiche/speciali |
Optional Chaining (?.) - ES2020
let persona = {
nome: "Mario",
indirizzo: {
città: "Milano"
}
};
// ❌ SENZA optional chaining (rischio errore)
console.log(persona.contatti.email); // TypeError! contatti è undefined
// ✅ CON optional chaining
console.log(persona.contatti?.email); // undefined (nessun errore)
console.log(persona.indirizzo?.città); // "Milano"
// Molto utile con dati incerti (API, database)
let utente = getUser(); // Potrebbe essere null
console.log(utente?.nome?.toUpperCase());
Modificare e Aggiungere Proprietà
Modificare Proprietà Esistenti
let persona = {
nome: "Mario",
età: 30,
professione: "Sviluppatore"
};
// Modifica con dot notation
persona.età = 31;
persona.professione = "Senior Developer";
console.log(persona);
// {nome: "Mario", età: 31, professione: "Senior Developer"}
// Modifica con bracket notation
persona["età"] = 32;
console.log(persona.età); // 32
Aggiungere Nuove Proprietà
let persona = {
nome: "Mario",
età: 30
};
// Aggiungi proprietà
persona.cognome = "Rossi";
persona.città = "Milano";
persona.hobbies = ["calcio", "lettura", "coding"];
console.log(persona);
// {nome: "Mario", età: 30, cognome: "Rossi", città: "Milano", hobbies: [...]}
Rimuovere Proprietà (delete)
let persona = {
nome: "Mario",
età: 30,
temp: "da rimuovere"
};
// Rimuovi proprietà
delete persona.temp;
delete persona.età;
console.log(persona); // {nome: "Mario"}
// Verifica esistenza proprietà
console.log("età" in persona); // false
console.log("nome" in persona); // true
⚠️ Oggetti Sono Mutabili!
Gli oggetti possono essere modificati anche se dichiarati con const.
const impedisce solo la riassegnazione della variabile!
const persona = {
nome: "Mario",
età: 30
};
// ✅ Modificare proprietà è OK
persona.età = 31;
persona.cognome = "Rossi";
console.log(persona); // {nome: "Mario", età: 31, cognome: "Rossi"}
// ❌ Riassegnare variabile NON è OK
// persona = {nome: "Luigi"}; // TypeError!
Metodi negli Oggetti
Un metodo è una funzione salvata come proprietà di un oggetto. I metodi definiscono i "comportamenti" dell'oggetto.
- Metodi - Sintassi Classica
Funzione come valore di proprietà.
Metodi Classici
let persona = {
nome: "Mario",
cognome: "Rossi",
età: 30,
// Metodo classico
saluta: function() {
return "Ciao, sono " + this.nome;
},
// Metodo con parametri
presenta: function(lavoro) {
return `Mi chiamo ${this.nome} e sono ${lavoro}`;
}
};
// Chiamata metodi
console.log(persona.saluta());
// "Ciao, sono Mario"
console.log(persona.presenta("sviluppatore"));
// "Mi chiamo Mario e sono sviluppatore"
- Metodi - Sintassi Abbreviata (ES6)
Modo più moderno e conciso. ⭐ CONSIGLIATO
Sintassi ES6
let persona = {
nome: "Mario",
cognome: "Rossi",
età: 30,
// Sintassi abbreviata (senza 'function')
saluta() {
return `Ciao, sono ${this.nome}`;
},
nomeCompleto() {
return `${this.nome} ${this.cognome}`;
},
compieAnni() {
this.età++;
return `Adesso ho ${this.età} anni!`;
}
};
console.log(persona.saluta()); // "Ciao, sono Mario"
console.log(persona.nomeCompleto()); // "Mario Rossi"
console.log(persona.compieAnni()); // "Adesso ho 31 anni!"
- La Keyword this
this si riferisce all'oggetto corrente.
Uso di this
let contoBancario = {
titolare: "Mario Rossi",
saldo: 1000,
deposita(importo) {
this.saldo += importo;
return `Depositati €${importo}. Nuovo saldo: €${this.saldo}`;
},
preleva(importo) {
if (importo > this.saldo) {
return "Saldo insufficiente!";
}
this.saldo -= importo;
return `Prelevati €${importo}. Nuovo saldo: €${this.saldo}`;
},
mostraSaldo() {
return `Conto di ${this.titolare}: €${this.saldo}`;
}
};
console.log(contoBancario.mostraSaldo()); // "Conto di Mario Rossi: €1000"
console.log(contoBancario.deposita(500)); // "Depositati €500. Nuovo saldo: €1500"
console.log(contoBancario.preleva(300)); // "Prelevati €300. Nuovo saldo: €1200"
⚠️ Attenzione con Arrow Functions!
Le arrow functions NON hanno il proprio this.
Evitale per metodi di oggetti!
let persona = {
nome: "Mario",
// ❌ MALE: arrow function
salutaMale: () => {
return `Ciao, sono ${this.nome}`; // this è undefined!
},
// ✅ BENE: function normale
salutaBene() {
return `Ciao, sono ${this.nome}`; // this funziona!
}
};
console.log(persona.salutaMale()); // "Ciao, sono undefined"
console.log(persona.salutaBene()); // "Ciao, sono Mario"
Iterare sugli Oggetti
- Object.keys() - Array delle Chiavi
Restituisce array con tutte le chiavi.
Object.keys()
let persona = {
nome: "Mario",
età: 30,
professione: "Sviluppatore",
città: "Milano"
};
let chiavi = Object.keys(persona);
console.log(chiavi);
// ["nome", "età", "professione", "città"]
// Conta proprietà
console.log(`L'oggetto ha ${chiavi.length} proprietà`);
// Itera sulle chiavi
chiavi.forEach(chiave => {
console.log(`${chiave}: ${persona[chiave]}`);
});
// nome: Mario
// età: 30
// professione: Sviluppatore
// città: Milano
- Object.values() - Array dei Valori
Restituisce array con tutti i valori.
Object.values()
let persona = {
nome: "Mario",
età: 30,
professione: "Sviluppatore"
};
let valori = Object.values(persona);
console.log(valori);
// ["Mario", 30, "Sviluppatore"]
// Somma valori numerici
let punteggi = {
matematica: 28,
fisica: 27,
informatica: 30
};
let voti = Object.values(punteggi);
let somma = voti.reduce((acc, voto) => acc + voto, 0);
let media = somma / voti.length;
console.log(`Media: ${media}`); // Media: 28.333...
- Object.entries() - Array di Coppie [chiave, valore]
Restituisce array di array [chiave, valore].
Object.entries()
let persona = {
nome: "Mario",
età: 30,
professione: "Sviluppatore"
};
let entries = Object.entries(persona);
console.log(entries);
// [["nome", "Mario"], ["età", 30], ["professione", "Sviluppatore"]]
// Itera con destructuring
entries.forEach(([chiave, valore]) => {
console.log(`${chiave} = ${valore}`);
});
// nome = Mario
// età = 30
// professione = Sviluppatore
// Converti oggetto in Map
let map = new Map(entries);
console.log(map.get("nome")); // "Mario"
- for...in Loop
Itera direttamente sulle chiavi.
Loop for...in
let persona = {
nome: "Mario",
età: 30,
professione: "Sviluppatore"
};
// for...in itera sulle chiavi
for (let chiave in persona) {
console.log(`${chiave}: ${persona[chiave]}`);
}
// nome: Mario
// età: 30
// professione: Sviluppatore
// Filtra solo stringhe
for (let chiave in persona) {
if (typeof persona[chiave] === "string") {
console.log(persona[chiave]);
}
}
// Mario
// Sviluppatore
📊 Confronto Metodi Iterazione
| Metodo | Restituisce | Uso Tipico |
|---|---|---|
Object.keys() |
Array chiavi | Conta proprietà, verifica esistenza |
Object.values() |
Array valori | Somme, medie, operazioni sui valori |
Object.entries() |
Array [chiave, valore] | Conversioni, destructuring |
for...in |
- | Iterazione diretta |
Copiare e Unire Oggetti
Shallow Copy con Spread Operator (...)
let originale = {
nome: "Mario",
età: 30
};
// Copia shallow (primo livello)
let copia = { ...originale };
copia.età = 31;
console.log(originale.età); // 30 (invariato)
console.log(copia.età); // 31
// Unione oggetti
let base = { nome: "Mario", età: 30 };
let extra = { professione: "Sviluppatore", città: "Milano" };
let completo = { ...base, ...extra };
console.log(completo);
// {nome: "Mario", età: 30, professione: "Sviluppatore", città: "Milano"}
Object.assign()
let obj1 = { a: 1, b: 2 };
let obj2 = { b: 3, c: 4 };
// Unisce obj2 in obj1 (modifica obj1!)
Object.assign(obj1, obj2);
console.log(obj1); // {a: 1, b: 3, c: 4}
// Copia senza modificare originale
let copia = Object.assign({}, obj1);
// Unione multipla
let finale = Object.assign({}, obj1, obj2, { d: 5 });
console.log(finale); // {a: 1, b: 3, c: 4, d: 5}
⚠️ Shallow vs Deep Copy
Spread e Object.assign fanno copie superficiali (shallow): oggetti annidati sono ancora riferimenti!
let originale = {
nome: "Mario",
indirizzo: {
città: "Milano"
}
};
// Shallow copy
let copia = { ...originale };
// Modifica oggetto annidato
copia.indirizzo.città = "Roma";
console.log(originale.indirizzo.città); // "Roma" (MODIFICATO!)
// ✅ Deep copy con JSON (limitato)
let deepCopy = JSON.parse(JSON.stringify(originale));
// ✅ Deep copy con structuredClone (moderno)
let deepCopy2 = structuredClone(originale);
Esempio Completo: Sistema Gestione Libri
Oggetto Libro Completo
let libro = {
// Proprietà
titolo: "Il Grande Gatsby",
autore: "F. Scott Fitzgerald",
anno: 1925,
pagine: 180,
genere: "Fiction",
letto: false,
voto: null,
// Metodo: Info completa
infoCompleta() {
return `"${this.titolo}" di ${this.autore} (${this.anno}) - ${this.genere} - ${this.pagine} pagine`;
},
// Metodo: Leggi libro
leggiLibro() {
this.letto = true;
return `✅ Hai letto "${this.titolo}"`;
},
// Metodo: Valuta libro
valuta(voto) {
if (voto < 1 || voto > 5) {
return "❌ Voto deve essere tra 1 e 5";
}
if (!this.letto) {
return "⚠️ Devi prima leggere il libro!";
}
this.voto = voto;
return `⭐ Hai dato ${voto} stelle a "${this.titolo}"`;
},
// Metodo: Tempo lettura stimato
tempoLettura() {
let minutiTotali = this.pagine * 2; // 2 min/pagina
let ore = Math.floor(minutiTotali / 60);
let minuti = minutiTotali % 60;
return `⏱️ Tempo lettura stimato: ${ore}h ${minuti}min`;
},
// Metodo: Stato lettura
statoLettura() {
if (!this.letto) {
return "📚 Da leggere";
}
if (this.voto) {
return `✅ Letto - Voto: ${"⭐".repeat(this.voto)}`;
}
return "✅ Letto - Non valutato";
},
// Metodo: Riepilogo
riepilogo() {
return `
╔═══════════════════════════════════════════╗
║ SCHEDA LIBRO ║
╠═══════════════════════════════════════════╣
║ Titolo: ${this.titolo.padEnd(31)} ║
║ Autore: ${this.autore.padEnd(31)} ║
║ Anno: ${this.anno}${' '.repeat(27)} ║
║ Genere: ${this.genere.padEnd(31)} ║
║ Pagine: ${this.pagine}${' '.repeat(27)} ║
║ Stato: ${this.statoLettura().padEnd(31)} ║
║ ${this.tempoLettura().padEnd(41)} ║
╚═══════════════════════════════════════════╝
`.trim();
}
};
// ===== TEST =====
console.log(libro.infoCompleta());
console.log(libro.tempoLettura());
console.log(libro.statoLettura());
console.log("\n" + libro.leggiLibro());
console.log(libro.valuta(5));
console.log("\n" + libro.riepilogo());
💡 Tecniche Usate
- Proprietà di vari tipi (string, number, boolean, null)
- Metodi con e senza parametri
thisper accedere a proprietà interne- Template literals per formattazione
- Validazione input nei metodi
- Calcoli (tempo lettura)
- Logica condizionale (stato lettura)
- Formattazione avanzata (box ASCII)
Esercizi Pratici
Esercizio 1: Calcolatrice Oggetto
Obiettivo: Crea un oggetto calcolatrice con metodi per operazioni
Requisiti:
- Proprietà
risultatoinizializzata a 0 - Metodo
somma(n) - Metodo
sottrai(n) - Metodo
moltiplica(n) - Metodo
dividi(n)(con controllo divisione per 0) - Metodo
reset()per azzerare - Metodo
mostraRisultato()
Mostra la soluzione
Soluzione Esercizio 1
let calcolatrice = {
risultato: 0,
somma(n) {
this.risultato += n;
return this; // Per chaining
},
sottrai(n) {
this.risultato -= n;
return this;
},
moltiplica(n) {
this.risultato *= n;
return this;
},
dividi(n) {
if (n === 0) {
console.log("❌ Impossibile dividere per zero!");
return this;
}
this.risultato /= n;
return this;
},
reset() {
this.risultato = 0;
return this;
},
mostraRisultato() {
console.log(`Risultato: ${this.risultato}`);
return this;
}
};
// Test con method chaining
calcolatrice
.somma(10)
.moltiplica(3)
.sottrai(5)
.dividi(5)
.mostraRisultato(); // Risultato: 5
calcolatrice.reset().mostraRisultato(); // Risultato: 0
Esercizio 2: Gestione Prodotto E-commerce
Obiettivo: Crea oggetto prodotto con gestione stock e prezzo
Requisiti:
- Proprietà: id, nome, prezzo, quantitàStock, categoria
- Metodo
prezzoScontato(percentuale) - Metodo
isDisponibile() - Metodo
aggiungiStock(quantità) - Metodo
rimuoviStock(quantità)con validazione - Metodo
schedaProdotto()con tutte le info
Mostra la soluzione
Soluzione Esercizio 2
let prodotto = {
id: 1001,
nome: "Laptop Pro",
prezzo: 1299.99,
quantitàStock: 15,
categoria: "Elettronica",
prezzoScontato(percentuale) {
let sconto = this.prezzo * (percentuale / 100);
let prezzoFinale = this.prezzo - sconto;
return `Prezzo scontato (${percentuale}%): €${prezzoFinale.toFixed(2)}`;
},
isDisponibile() {
return this.quantitàStock > 0;
},
aggiungiStock(quantità) {
this.quantitàStock += quantità;
return `✅ Aggiunte ${quantità} unità. Stock totale: ${this.quantitàStock}`;
},
rimuoviStock(quantità) {
if (quantità > this.quantitàStock) {
return `❌ Stock insufficiente! Disponibili: ${this.quantitàStock}`;
}
this.quantitàStock -= quantità;
return `✅ Rimosse ${quantità} unità. Rimanenti: ${this.quantitàStock}`;
},
schedaProdotto() {
let disponibilità = this.isDisponibile() ? "✅ Disponibile" : "❌ Esaurito";
return `
╔════════════════════════════════╗
║ SCHEDA PRODOTTO ║
╠════════════════════════════════╣
║ ID: ${this.id}${' '.repeat(20)} ║
║ Nome: ${this.nome.padEnd(20)} ║
║ Categoria: ${this.categoria.padEnd(20)} ║
║ Prezzo: €${this.prezzo.toFixed(2).padEnd(18)} ║
║ Stock: ${this.quantitàStock}${' '.repeat(20)} ║
║ Stato: ${disponibilità.padEnd(20)} ║
╚════════════════════════════════╝
`.trim();
}
};
// Test
console.log(prodotto.schedaProdotto());
console.log("\n" + prodotto.prezzoScontato(20));
console.log(prodotto.rimuoviStock(5));
console.log(prodotto.aggiungiStock(10));
console.log("\n" + prodotto.schedaProdotto());
Esercizio 3: Registro Studenti
Obiettivo: Crea oggetto studente con gestione voti
Requisiti:
- Proprietà: nome, cognome, matricola, voti (array vuoto)
- Metodo
aggiungiVoto(materia, voto) - Metodo
calcolaMedia() - Metodo
mostraVoti() - Metodo
votoMassimo()evotoMinimo()
Mostra la soluzione
Soluzione Esercizio 3
let studente = {
nome: "Mario",
cognome: "Rossi",
matricola: "S12345",
voti: [], // Array di oggetti {materia, voto}
aggiungiVoto(materia, voto) {
if (voto < 18 || voto > 30) {
return "❌ Voto non valido (18-30)";
}
this.voti.push({ materia, voto });
return `✅ Voto ${voto} aggiunto per ${materia}`;
},
calcolaMedia() {
if (this.voti.length === 0) {
return 0;
}
let somma = this.voti.reduce((acc, v) => acc + v.voto, 0);
return (somma / this.voti.length).toFixed(2);
},
mostraVoti() {
if (this.voti.length === 0) {
return "Nessun voto presente";
}
let output = "📚 ELENCO VOTI:\n";
this.voti.forEach((v, i) => {
output += `${i + 1}. ${v.materia}: ${v.voto}\n`;
});
return output;
},
votoMassimo() {
if (this.voti.length === 0) return null;
return Math.max(...this.voti.map(v => v.voto));
},
votoMinimo() {
if (this.voti.length === 0) return null;
return Math.min(...this.voti.map(v => v.voto));
},
riepilogo() {
return `
╔══════════════════════════════════╗
║ REGISTRO STUDENTE ║
╠══════════════════════════════════╣
║ Nome: ${(this.nome + ' ' + this.cognome).padEnd(27)} ║
║ Matricola: ${this.matricola.padEnd(22)} ║
║ Esami sostenuti: ${this.voti.length}${' '.repeat(15)} ║
║ Media: ${this.calcolaMedia().padEnd(26)} ║
║ Voto max: ${this.votoMassimo() || 'N/A'}${' '.repeat(22)} ║
║ Voto min: ${this.votoMinimo() || 'N/A'}${' '.repeat(22)} ║
╚══════════════════════════════════╝
`.trim();
}
};
// Test
console.log(studente.aggiungiVoto("Matematica", 28));
console.log(studente.aggiungiVoto("Fisica", 25));
console.log(studente.aggiungiVoto("Informatica", 30));
console.log("\n" + studente.mostraVoti());
console.log("\n" + studente.riepilogo());
🎯 Riepilogo Lezione
Creazione:
- {} literal
- new Object()
- Object.create()
Accesso:
- obj.prop (dot)
- obj["prop"] (bracket)
- obj?.prop (optional)
Metodi:
- Funzioni in oggetti
- Keyword this
- Sintassi ES6
Iterazione:
- Object.keys()
- Object.values()
- Object.entries()
- for...in