[ Web Proxy ]
URL:
Viewing: https://it.javascript.info/instanceof [Back]  [Original]

Verifica delle classi: "instanceof"
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

    Verifica delle classi: "instanceof"

    Loperatore instanceof ci consente di verificare se un oggetto appartiene ad una specifica classe. Anche lereditariet viene presa in considerazione.

    Questo tipo di controllo potrebbe essere necessario in diversi casi. Ad esempio, pu essere utilizzato per costruire una funzione polimorfa, ossia una funzione che tratta gli argomenti differentemente in base al loro tipo.

    L'operatore instanceof

    La sintassi :

    obj instanceof Class

    Ritorna true se obj di tipo Class o una sua sotto-classe.

    Ad esempio:

    class Rabbit {}
    let rabbit = new Rabbit();
    
    //  un oggetto di tipo Rabbit?
    alert( rabbit instanceof Rabbit ); // true

    Funziona anche con i costruttori:

    // invece di usare class
    function Rabbit() {}
    
    alert( new Rabbit() instanceof Rabbit ); // true

    E con le classi integrate come Array:

    let arr = [1, 2, 3];
    alert( arr instanceof Array ); // true
    alert( arr instanceof Object ); // true

    Da notare che arr appartiene anche alla classe Object. Questo accade perch Array eredita da Object.

    Normalmente instanceof esamina la catena dei prototype per effettuare questa verifica. Possiamo anche definire una logica personalizzata nel metodo statico Symbol.hasInstance.

    Lalgoritmo di obj instanceof Class funziona, a grandi linee, in questo modo:

    1. Se stato definito un metodo statico Symbol.hasInstance, allora questo verr invocato: Class[Symbol.hasInstance](obj). Dovrebbe ritornare true o false, questo tutto. In questo modo possiamo personalizzare il comportamento di instanceof.

      For example:

      // impostiamo il controllo instanceOf in modo che assuma che
      // qualsiasi cosa con la propriet canEat sia un animale
      class Animal {
        static [Symbol.hasInstance](obj) {
          if (obj.canEat) return true;
        }
      }
      
      let obj = { canEat: true };
      
      alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj)  stato invocato
    2. Molte classi non hanno Symbol.hasInstance. In questo caso, viene utilizzata la logica standard: obj instanceOf Class che controlla se Class.prototype equivale ad uno dei prototype nella catena dei prototype di obj.

      In altre parole, li confronta tutti uno alla volta:

      obj.__proto__ === Class.prototype?
      obj.__proto__.__proto__ === Class.prototype?
      obj.__proto__.__proto__.__proto__ === Class.prototype?
      ...
      // se una di questa  true, allora viene ritornato true
      // altrimenti, una volta arrivati al termine della catena, ritorna false

      Nellesempio sopra rabbit.__proto__ === Rabbit.prototype, quindi riceviamo immediatamente una risposta.

      In caso di ereditariet, il riscontro avverr al secondo passo:

      class Animal {}
      class Rabbit extends Animal {}
      
      let rabbit = new Rabbit();
      alert(rabbit instanceof Animal); // true
      
      // rabbit.__proto__ === Animal.prototype (no match)
      // rabbit.__proto__.__proto__ === Animal.prototype (match!)

    Qui vediamo raffigurato cosa rabbit instanceof Animal confronta con Animal.prototype:

    []

    Comunque, abbiamo a disposizione anche il metodo objA.isPrototypeOf(objB), che ritorna true se objA si trova nella catena dei prototype di objB. Quindi la verifica obj instanceof Class pu essere riformulata come Class.prototype.isPrototypeOf(obj).

    Un fatto divertente, che il costruttore stesso della Class, non viene coinvolto nella verifica! Solamente la catena dei prototype e Class.prototype vengono valutati.

    Questo pu portare a diverse conseguenze quando la propriet prototype viene modificata dopo la creazione delloggetto.

    Come nellesempio:

    function Rabbit() {}
    let rabbit = new Rabbit();
    
    // modifichiamo il prototype
    Rabbit.prototype = {};
    
    // ...non  p un rabbit!
    alert( rabbit instanceof Rabbit ); // false

    Bonus: Object.prototype.toString per il tipo

    Sappiamo gi che gli oggetti semplici vengono convertiti a stringa come [object Object]:

    let obj = {};
    
    alert(obj); // [object Object]
    alert(obj.toString()); // lo stesso

    Questa la loro implementazione del metodo toString. Ma esiste una funzionalit nascosta che rende toString molto pi potente di cosi. Possiamo utilizzarlo come unestensione di typeof e come alternativa di instanceof.

    Sembra strano? Lo ! Capiamo perch.

    Secondo le specifiche, il metodo integrato toString pu essere estratto dalloggetto ed eseguito nel contesto di un qualsiasi altro valore. Ed il suo risultato dipende da quel valore.

    • Per un numero, sar [object Number]
    • Per un boolean, sar [object Boolean]
    • Per null: [object Null]
    • Per undefined: [object Undefined]
    • Per gli array: [object Array]
    • etc (personalizzabile).

    Dimostriamolo:

    // copiamo il metodo toString in una variabile per comodit
    let objectToString = Object.prototype.toString;
    
    // di che tipo  questo?
    let arr = [];
    
    alert( objectToString.call(arr) ); // [object Array]

    Qui abbiamo utilizzato call come descritto nel capitolo *Decorators* e forwarding, call/apply per eseguire la funzione objectToString nel contesto this=arr.

    Internamente, lalgoritmo toString esamina this e ritorna il risultato corrispondente. Altri esempi:

    let s = Object.prototype.toString;
    
    alert( s.call(123) ); // [object Number]
    alert( s.call(null) ); // [object Null]
    alert( s.call(alert) ); // [object Function]

    Symbol.toStringTag

    Il comportamento di Object toString pu essere personalizzato utilizzando una propriet speciale delloggetto Symbol.toStringTag.

    Ad esempio:

    let user = {
      [Symbol.toStringTag]: "User"
    };
    
    alert( {}.toString.call(user) ); // [object User]

    Per molti oggetti specifici di un ambiente, esiste questa propriet. Qui vediamo alcuni esempi specifici per il browser:

    // toStringTag per l'oggetto specifico d'ambiente:
    alert( window[Symbol.toStringTag]); // Window
    alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
    
    alert( {}.toString.call(window) ); // [object Window]
    alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]

    Come potete vedere, il risultato esattamente Symbol.toStringTag (se esiste), racchiuso in [object ...].

    Al termine avremo typeof on steroids che non funziona solamente con i tipi di dato primitivo, ma anche con gli oggetti integrati, inoltre pu essere personalizzato.

    Possiamo utilizzare {}.toString.call piuttosto di instanceof per gli oggetti integrati quando vogliamo ottenerne il tipo come stringa invece di effettuare una semplice verifica.

    Riepilogo

    Ricapitoliamo i metodi di verifica del tipi:

    funzionano con ritorna
    typeof primitivi stringa
    {}.toString primitivi, oggetti integrati, oggetti con Symbol.toStringTag stringa
    instanceof oggetti true/false

    Come possiamo vedere, {}.toString tecnicamente pi avanzato di typeof.

    Invece loperatore instanceof funziona veramente bene quando lavoriamo con una classe e vogliamo controllarne lereditariet.

    Esercizi

    importanza: 5

    Nel codice sottostante, perch instanceof ritorna true? Possiamo facilmente vedere che a non creato da B().

    function A() {}
    function B() {}
    
    A.prototype = B.prototype = {};
    
    let a = new A();
    
    alert( a instanceof B ); // true
    soluzione

    S, sembra strano.

    Ma instanceof non prende in considerazione la funzione, ma piuttosto il suo prototype, che trova riscontro nella catena dei prototye.

    In questo caso a.__proto__ == B.prototype, quindi instanceof ritorna true.

    Quindi, secondo la logica di instanceof, il prototype a definire il tipo, non il costruttore.

    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