Funzionalità aggiuntive delle classi in JavaScript

Funzionalità aggiuntive delle classi in JavaScript

In questo articolo spiegheremo le funzionalità aggiuntive delle classi in JavaScript.

YouTube Video

Funzionalità aggiuntive delle classi in JavaScript

Proprietà private in JavaScript

In JavaScript, le proprietà private sono proprietà accessibili solo all'interno dell'oggetto o della classe. Questo consente un design del codice più sicuro e robusto fornendo incapsulamento, in modo che le modifiche o i riferimenti diretti dal codice esterno non siano possibili.

Introdotto in ECMAScript 2020 (ES11) nel 2020, è stato introdotto l'uso di # (hash) per definire campi privati all'interno di una classe. Questo offre un modo più chiaro, sostituendo le convenzioni private tradizionali di JavaScript (come i nomi delle variabili che iniziano con un underscore).

Vantaggi delle proprietà private

Di seguito sono elencati i vantaggi delle proprietà private.

  • Incapsulamento: Nasconde lo stato interno dall'esterno e mantiene la coerenza dei dati.
  • Sicurezza: Impedisce che le proprietà vengano modificate accidentalmente dal codice esterno.
  • Migliore Manutenibilità: Nasconde l'implementazione di oggetti o classi e chiarisce l'interfaccia esposta all'esterno.

Come utilizzare le proprietà private

Definizione di proprietà private nelle classi

I campi privati sono definiti utilizzando un nome che inizia con #. Questo campo non può essere direttamente accessibile dalle istanze della classe o delle sue sottoclassi.

 1class Person {
 2    // Define private property
 3    #name;
 4
 5    constructor(name) {
 6        this.#name = name;
 7    }
 8
 9    // Method to access the private property
10    getName() {
11        return this.#name;
12    }
13
14    // Method to change the private property
15    setName(newName) {
16        this.#name = newName;
17    }
18}
19
20const john = new Person("John");
21console.log(john.getName()); // John
22
23// Cannot access private property directly
24console.log(john.#name); // SyntaxError: Private field '#name' must be declared in an enclosing class

Nel codice sopra, #name è una proprietà privata che non può essere direttamente accessibile dall'esterno della classe Person. Puoi accedere o modificare il nome solo tramite i metodi getName e setName.

Definizione di metodi privati

Come le proprietà private, anche i metodi privati sono definiti utilizzando un nome che inizia con #. I metodi privati possono essere chiamati solo all'interno della classe.

 1class Counter {
 2    #count = 0;
 3
 4    increment() {
 5        this.#count++;
 6        this.#logCount(); // Calling private method
 7    }
 8
 9    // Private method
10    #logCount() {
11        console.log(`Current count: ${this.#count}`);
12    }
13}
14
15const counter = new Counter();
16counter.increment(); // Current count: 1
17
18// Cannot access private method directly
19counter.#logCount(); // SyntaxError: Private field '#logCount' must be declared in an enclosing class

Qui, #logCount è definito come metodo privato e non può essere accessibile dall'esterno della classe. Questo metodo viene utilizzato solo all'interno della classe.

Vantaggi e considerazioni delle proprietà private

Vantaggio

  • Poiché non può essere accessibile direttamente dall'esterno della classe, si prevengono modifiche o operazioni indesiderate.
  • Poiché le parti non visibili dall'esterno possono essere ben nascoste, puoi gestire chiaramente le parti che esponi come API.

Note

  • Poiché i campi privati sono completamente nascosti dall'esterno della classe, test e debug possono diventare difficili. Pertanto, è importante fornire un'API che possa essere accuratamente testata nella fase di progettazione.
  • I campi privati si comportano in modo diverso rispetto ad altre parti di JavaScript con caratteristiche basate su prototipi perché sono unici per ogni istanza.

Implementazione Tradizionale Pseudosanonima delle Proprietà Private

Prima dell'introduzione dei campi privati con #, JavaScript non aveva una sintassi ufficiale per le proprietà private. Pertanto, in passato, le proprietà pseudo-private erano implementate nei modi seguenti.

Convenzione dell'uso di underscore

Gli sviluppatori indicavano convenzionalmente 'privato' anteponendo un underscore ai nomi delle variabili.

 1class Car {
 2    constructor(brand) {
 3        this._brand = brand; // Using an underscore to indicate private
 4    }
 5
 6    getBrand() {
 7        return this._brand;
 8    }
 9}
10
11const car = new Car("Toyota");
12console.log(car.getBrand()); // Toyota
13console.log(car._brand); // Toyota (Accessible from outside)

Questo metodo è semplicemente una 'convenzione' e, in pratica, le proprietà possono comunque essere accessibili dall'esterno.

Implementazione di proprietà private utilizzando le chiusure

È anche possibile ottenere proprietà private utilizzando chiusure con ambito di funzione.

 1function createPerson(name) {
 2    let _name = name; // Private variable within function scope
 3
 4    return {
 5        getName: function() {
 6            return _name;
 7        },
 8        setName: function(newName) {
 9            _name = newName;
10        }
11    };
12}
13
14const person = createPerson("Alice");
15console.log(person.getName()); // Alice
16person.setName("Bob");
17console.log(person.getName()); // Bob
18
19// Cannot access directly from outside
20console.log(person._name); // undefined

Con questo metodo, la variabile _name è racchiusa nell'ambito della funzione e non può essere direttamente accessibile dall'esterno.

Riepilogo

Le proprietà private in JavaScript sono molto efficaci nel fornire incapsulamento nel design di classi e oggetti, aiutando a proteggere i dati in modo sicuro. La notazione # per i campi privati introdotta in ES2020 offre un metodo di gestione della privacy più chiaro e sicuro rispetto alle convenzioni tradizionali e alle chiusure.

Optional Chaining in JavaScript

L'Optional Chaining è una sintassi molto utile in JavaScript per accedere alle proprietà di oggetti profondamente annidati. Migliora la leggibilità e la manutenibilità del codice consentendo un accesso sicuro senza dover verificare singolarmente l'esistenza di proprietà specifiche.

Sintassi di base dell'Optional Chaining

L'Optional Chaining può essere utilizzato posizionando ? prima del punto (.) o della notazione tra parentesi usata per l'accesso alle proprietà. Questa notazione restituisce undefined quando una proprietà attraversata è null o undefined, consentendo al programma di continuare l'elaborazione in sicurezza senza generare errori.

Esempio:

 1const user = {
 2    name: 'John',
 3    address: {
 4        street: '123 Main St',
 5        city: 'New York'
 6    }
 7};
 8
 9// Without using optional chaining
10const city = user && user.address && user.address.city;
11console.log(city);  // New York
12
13// Using optional chaining
14const cityWithOptionalChaining = user?.address?.city;
15console.log(cityWithOptionalChaining);  // New York

In questo esempio, stiamo accedendo all'address e alla sua proprietà city dell'oggetto user. Senza utilizzare l'optional chaining, dovresti eseguire molteplici controlli di esistenza, ma con l'optional chaining puoi accedere in modo sicuro alla proprietà con un'unica istruzione.

Utilizzo dell'Optional Chaining con array e funzioni

L'optional chaining è applicabile non solo alle proprietà degli oggetti, ma anche agli elementi degli array e alle chiamate di funzione.

Esempio con array:

1const users = [{ name: 'Alice' }, { name: 'Bob' }];
2
3// Accessing the non-existent third element
4const thirdUser = users[2]?.name;
5console.log(thirdUser);  // undefined

Esempio con funzioni:

 1const user = {
 2    greet: function() {
 3        return 'Hello!';
 4    }
 5};
 6
 7// Call the function only if greet exists
 8const greeting = user.greet?.();
 9console.log(greeting);  // Hello!
10
11// Return undefined if greet does not exist
12const nonExistentGreeting = user.nonExistentMethod?.();
13console.log(nonExistentGreeting);  // undefined

Combinare l'Optional Chaining con i valori predefiniti

Quando si utilizza l'optional chaining, è comune usare l'operatore logico OR (||) o l'operatore nullish coalescing (??) per specificare valori predefiniti nel caso in cui una proprietà non esista.

Esempio:

 1const user = {
 2    name: 'John',
 3    address: {
 4        city: 'New York'
 5    }
 6};
 7
 8// Set a default value for a non-existent property
 9const state = user?.address?.state || 'Unknown';
10console.log(state);  // Unknown
11
12// Example using the nullish coalescing operator
13const zipCode = user?.address?.zipCode ?? '00000';
14console.log(zipCode);  // 00000

L'operatore || considera false, 0, '', ecc., come valori falsy, mentre l'operatore ?? utilizza il valore predefinito solo se l'operando è null o undefined.

Vantaggi dell'Optional Chaining

  • Accesso sicuro agli oggetti annidati: Utilizzando l'optional chaining, non è più necessario eseguire controlli espliciti di esistenza, rendendo il codice più conciso.
  • Evitare errori: Può evitare errori a runtime anche se una proprietà è null o undefined.
  • Leggibilità e manutenibilità migliorate: Soprattutto quando si ha a che fare con molti oggetti annidati, la leggibilità del codice è notevolmente migliorata.

Attenzioni con l'Optional Chaining

  • L'uso frequente dell'optional chaining potrebbe essere un segnale che il design della struttura dei dati è eccessivamente complesso. Dovresti puntare a un modello di dati semplice.
  • Poiché alcuni browser più vecchi e i motori JavaScript non lo supportano, potrebbe essere necessario utilizzare polyfill o transpiler.

Conclusione

L'optional chaining è una funzionalità potente che semplifica l'accesso sicuro alle proprietà e alle funzioni di oggetti annidati in JavaScript. È particolarmente efficace nell'accesso a strutture di dati profondamente annidate, contribuendo a prevenire errori e a migliorare la leggibilità del codice.

Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.

YouTube Video