L’ereditarietà dei costruttori in JavaScript con constructor e prototype

JavaScript mette a disposizione un ottimo strumento per utilizzare l’ereditarietà. Tutti i tipi JavaScript (ad eccezione di null e undefined) hanno la proprietà constructor che consente di identificare il tipo di classe dell’oggetto e che viene ereditata dalle sottoclassi.

Vediamo come accedere a constructor:

    var myNum = 150;
    console.log(myNum.constructor === Number); // => true

I numeri hanno come constructor Number, i booleani hanno Boolean, le stringhe hanno String e i simboli hanno Symbol (introdotti in ES6).

L’ereditarietà con i tipi primitivi

I tipi primitivi possono essere wrappati (come accade in Java ) in oggetti, in particolare possono essere utilizzati solo con i numeri, le stringhe e i booleani:

    new Number(1);
    new String("Datrevo");
    new Boolean(true);

L’utilità dei tipi wrapper è quella di poter inserire proprietà e metodi personalizzati alle classi, quindi di poter utilizzare i tipi primitivi come veri e propri oggetti. Attenzione però che i tipi wrapper hanno lo stesso constructor dei tipi primitivi (per questo motivo per conoscere il tipo di un oggetto è consigliato utilizzare typeof).

    var myBoolean = true;
    console.log(myBoolean.constructor === Boolean); // => true

    var myBooleanWrapper = new Boolean(true);
    console.log(myBooleanWrapper.constructor === Boolean); // => true

Ereditare dagli altri oggetti sfruttando il prototipo con prototype

In JavaScript un oggetto può ereditare tutte le proprietà di un altro oggetto, l’oggetto da cui si eredita rappresenta il prototipo (prototype) dell’oggetto appena creato. Ogni qualvolta viene creato un nuovo oggetto viene creato un collegamento con il suo prototipo e alle sue proprietà. Tutti gli oggetti ereditano da Object che definisce un insieme di funzioni come hasOwnProperty() utilizzata per verificare se l’oggetto contiene una determinata proprietà.

    var myObject = {
        myField: 1
    };
    console.log(myObject.hasOwnProperty('myField')); // => true

Per creare un nuovo oggetto basato su un prototipo di un altro oggetto è possibile utilizzare la funzione Object.create(myPrototype). Ad esempio:

    var myObject1 = {
        myField1: 1
    };

    var myObject2 = Object.create(myObject1);
    console.log(myObject2.myField1); // => 1

Dopo aver definito un oggetto myObject1 che eredita automaticamente da Object.prototype, creiamo un nuovo oggetto (myObject2) il cui prototipo è dato dall’oggetto definito in precedenza (myObject1). A questo punto è possibile accedere ai valori dell’oggetto da cui si è estesi e visualizzare le sue proprietà. la proprietà viene cercata in un primo momento nell’oggetto stesso, se non presente viene risalita la catena di prototipi fino ad arrivare, eventualmente, ad Object.

I vettori ereditano da Array.prototype (che offre metodi come indexOf, forEach, ecc.), anche Array eredita eredita da Object.prototype, così come la funzioni ereditano da Function.prototype (che contiene metodi come call, bind, ecc.). Object è l’unico oggetto che ha prototipo null.

Quando si crea una sottoclasse la proprietà constructor non viene automaticamente settata al nuovo oggetto e bisogna farlo manualmente. Ad esempio:

    function myFuncion1() {
    };
    function myFuncion2() {
    };
    myFuncion2.prototype = Object.create(myFuncion1.prototype);
    console.log(myFuncion2.prototype.constructor === myFuncion1); // => true
    console.log(myFuncion2.prototype.constructor === myFuncion2); // => false

    myFuncion2.prototype.constructor = myFuncion2;
    console.log(myFuncion2.prototype.constructor === myFuncion1); // => false
    console.log(myFuncion2.prototype.constructor === myFuncion2); // => true

Il mancato aggiornamento del prototype di myFuncion2 è dovuto al myFuncion1.prototype.clone() che richiama this.constructor() per creare un clone di se stesso. In quel momento però, il costruttore punta ancora a myFuncion1.

L’operatore instanceof in JavaScript

L’operatore instanceof consente di determinare se un oggetto ha lo stesso prototipo di un altro oggetto. Quest’operatore però, restituisce true anche quando si tratta di una sottoclasse:

    function myFunction1() {
    };
    function myFunction2() {
    };
    myFunction2.prototype = Object.create(myFunction1.prototype);
    myFunction2.prototype.constructor = myFunction2;

    var myObject1 = new myFunction1();
    var myObject2 = new myFunction2();
    console.log(myObject2 instanceof myFunction1); // => true
    console.log(myObject2 instanceof myFunction2); // => true

In questi casi la proprietà constructor ci consente di determinare la vera istanza della classe:

    console.log(myObject2.constructor === myFunction1); // => false
    console.log(myObject2.constructor === myFunction2); // => true

Gli oggetti funzione in JavaScript hanno un nome che viene memorizzato nel campo name del constructor. Questo campo ritorna il nome della funziona o una stringa vuota per le funzioni anonime.

    function myFunction1() {
    };
    var myVar = new myFunction1();
    console.log(myVar.constructor.name); // => myFunction1

Pubblicato in Front-end, JavaScript Taggato con: , , , , , ,

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

*