[ Web Proxy ]
URL:
Viewing: https://it.javascript.info/reference-type [Back]  [Original]

Il tipo Reference
IT

Vorremo rendere disponibile questo progetto open-source per persone in tutto il mondo.

Aiutaci a tradurre il contenuto di questo tutorial nella tua lingua!

    Cerca in Javascript.info:
    Cerca nel tutorial:
    Light themeDark theme
    DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek

    Il tipo Reference

    Caratteristica avanzata di linguaggio

    Questo articolo tratta un argomento avanzato, utile per capire meglio alcuni casi limite.

    Non di fondamentale importanza. Molti sviluppatori esperti vivono bene senza esserne a conoscenza. Continua la lettura se sei interessato a sapere come funzionano le cose internamente.

    Uninvocazione di un metodo valutata dinamicamente pu perdere il this.

    Ad esempio:

    let user = {
      name: "John",
      hi() { alert(this.name); },
      bye() { alert("Bye"); }
    };
    
    user.hi(); // funziona
    
    // ora invochiamo user.hi o user.bye in base al nome
    (user.name == "John" ? user.hi : user.bye)(); // Errore!

    Nellultima riga abbiamo un operatore condizionale che sceglie tra user.hi o user.bye. In questo caso il risultato user.hi.

    Successivamente il metodo viene invocato immediatamente con le parentesi (). Ma non funziona correttamente!

    Come potete vedere, linvocazione genera un errore, perch il valore di "this" allinterno della chiamata diventa undefined.

    Questo invece funziona (object punto metodo):

    user.hi();

    Questo no (valutazione del metodo):

    (user.name == "John" ? user.hi : user.bye)(); // Errore!

    Perch? Se vogliamo capire il motivo, dobbiamo addentrarci nei dettagli del funzionamento della chiamata obj.method().

    Il tipo Reference spiegato

    Guardando da pi vicino, possiamo notare due operazioni nellistruzione obj.method():

    1. Primo, il punto '.' recupera la propriet obj.method.
    2. Successivamente le parentesi () la eseguono.

    Quindi, come vengono passate le informazioni riguardo al this dalla prima alla seconda parte?

    Se spostiamo queste istruzioni in righe separate, allora this verr sicuramente perso:

    let user = {
      name: "John",
      hi() { alert(this.name); }
    }
    
    // dividiamo l'accesso e l'invocazione in due righe
    let hi = user.hi;
    hi(); // Errore, perch this  undefined

    Qui hi = user.hi assegna la funzione alla variabile, e nellultima riga completamente autonoma, quindi non si ha alcun this.

    Per rendere linvocazione user.hi() funzionante, JavaScript applica un trucco il punto '.' non ritorna una funzione, ma piuttosto un valore del tipo speciale Reference.

    Il tipo Reference un tipo descritto dalla specifica. Non possiamo utilizzarlo esplicitamente, ma viene utilizzato internamente dal linguaggio.

    Il valore del tipo Reference una combinazione di tre valori (base, name, strict), dove:

    • base loggetto.
    • name il nome della propriet.
    • strict vale true se use strict attivo.

    Il risultato dellaccesso alla propriet user.hi non una funzione, ma un valore di tipo Reference. Per user.hi in strict mode vale:

    // valore di tipo Reference
    (user, "hi", true)

    Quando le parentesi () vengono invocate in un tipo Reference, queste ricevono tutte le informazioni riguardo loggetto ed il metodo, e possono quindi impostare correttamente il valore di this (=user in questo caso).

    Il tipo Reference uno speciale tipo intermedio utilizzato internamente, con lo scopo di passare le informazioni dal punto . allinvocazione con le parentesi ().

    Qualsiasi altra operazione come un assegnazione hi = user.hi scarta completamente il tipo Reference, accede al valore user.hi (una funzione) e lo ritorna. Quindi qualsiasi ulteriore operazione perder this.

    Quindi, come risultato, il valore di this viene passato correttamente solo se la funzione viene invocata direttamente utilizzando il punto obj.method() o la sintassi con le parentesi quadre obj['method']() (in questo caso si equivalgono). Esistono diversi modi per evitare questo problema, come func.bind().

    Riepilogo

    Il tipo Reference un tipo interno del linguaggio.

    La lettura di una propriet, con il punto . in obj.method() non ritorna esattamente il valore della propriet, ma uno speciale tipo reference che memorizza sia il valore della propriet che loggetto a cui accedere.

    Questo accade per consentire che la successiva invocazione con () imposti correttamente il this.

    Per tutte le altre operazioni, il tipo reference diventa automaticamente il valore della propriet (una funzione nel nostro caso).

    Il meccanismo descritto nascosto ai nostri occhi. Ha importanza solo in alcuni casi, ad esempio quando un metodo viene ottenuto dinamicamente dalloggetto, utilizzando unespressione.

    Esercizi

    importanza: 2

    Qual il risultato di questo codice?

    let user = {
      name: "John",
      go: function() { alert(this.name) }
    }
    
    (user.go)()

    P.S. C una trappola :)

    soluzione

    Errore!

    Provatelo:

    let user = {
      name: "John",
      go: function() { alert(this.name) }
    }
    
    (user.go)() // error!

    La maggior parte dei browser non vi dar informazioni necessarie per capire cosa andato storto.

    Lerrore viene causato dalla mancanza di un punto e virgola dopo user = {...}.

    JavaScript non inserisce automaticamente un punto e virgola prima di (user.go)(), quindi legger il codice in questo modo:

    let user = { go:... }(user.go)()

    Possiamo anche vedere questa come una comune espressione, sintatticamente una chiamata alloggetto { go: ... } come una funzione con argomento (user.go). E questo avviene nella stessa riga di let user, quindi loggetto user non ancora stato definito, quindi c un errore.

    Se inseriamo un punto e virgola, tutto funziona correttamente:

    let user = {
      name: "John",
      go: function() { alert(this.name) }
    };
    
    (user.go)() // John

    Da notare che le parentesi su (user.go) non fanno nulla. Solitamente servono ad organizzare lordine delle operazioni, in questo caso presente un . che verrebbe comunque eseguito per primo, non hanno quindi alcun effetto. Lunico errore stava nel punto e virgola.

    importanza: 3

    Nel codice sotto vogliamo chiamare il metodo user.go() volte di fila.

    Ma le chiamate (1) e (2) funzionano diversamente da (3) e (4). Perch?

    let obj, method;
    
    obj = {
      go: function() { alert(this); }
    };
    
    obj.go();               // (1) [object Object]
    
    (obj.go)();             // (2) [object Object]
    
    (method = obj.go)();    // (3) undefined
    
    (obj.go || obj.stop)(); // (4) undefined
    soluzione

    Vediamo la spiegazione.

    1. Questa una normale chiamata ad un metodo delloggetto.

    2. Stessa cosa, le parentesi non cambiano lordine delle operazioni, il punto viene eseguito per primo in ogni caso.

    3. Qui abbiamo una chiamata pi complessa (expression).method(). La chiamata viene interpretata come fosse divisa in due righe:

      f = obj.go; // calculate the expression
      f();        // call what we have

      Qui f() viene eseguita come una funzione, senza this.

    4. Molto simile a (3), alla sinistra del punto . abbiamo un espressione.

    Per spiegare il comportamento di (3) e (4) dobbiamo ricordare che la propriet di accesso (il punto o le parentesi quadre) ritornano un valore di tipo riferimento.

    Qualsiasi operazione tranne la chiamata ad un metodo (come lassegnazione = o ||) trasforma questo riferimento in un valore oridnario, che non porta pi le informazioni necessarie per impostare this.

    Mappa del tutorial

    Commenti

    leggi questo prima di lasciare un commento
    • Per qualsiasi suggerimento - per favore, apri una issue su GitHub o una pull request, piuttosto di lasciare un commento.
    • Se non riesci a comprendere quanto scitto nell'articolo ti preghiamo di fornire una spiegazione chiara.
    • Per inserire delle righe di codice utilizza il tag <code>, per molte righe includile nel tag <pre>, per pi di 10 righe utilizza una sandbox (plnkr, jsbin, codepen)

    Web Proxy Viewer  |  New URL  |  Original Page