lunedì, novembre 17, 2014

Ereditiamo o no?

In Javascript, non esistendo le classi, non esiste l'ereditarietà tra classi.

Esiste l'ereditarietà tra oggetti: un oggetto puo' ereditare, in fase di creazione, tutte le proprietà di un altro oggetto che costituisce il prototipo (prototype) dell'oggetto appena creato.

Ogni oggetto appena creato ha dunque un collegamento con il suo prototipo, oltre alle proprie proprietà (own properties).

Di default, ogni oggetto definito con json o con new Object(), ha come prototipo l'oggetto Object.prototype, che presenta una serie di proprietà (di tipo funzioni e quindi metodi) come hasOwnProperty(prop) che ritorna true se l'oggetto su cui si invoca contiene direttamente la proprietà indicata come argomento


 var automobile = {cilindrata: 1300, colore: 'rosso'};  
   
 console.log(automobile.hasOwnProperty('colore'));  

In questo caso verrà stampato sulla console il valore true.

Per la lista completa delle proprietà di Object.prototype rimando alla Guida Ufficile Javascript:
alcune di queste proprietà non sono standard, evitate di usarle per scrivere codice che funzioni su ogni browser.

Per creare un oggetto e assegnargli direttamente un prototipo è possibile usare la funzione Object.create(prototipo)


// o1 eredita da Object.prototype  
 var o1 = {b:3, c:4};  
   
 // o2 eredita da o1  
 var o2 = Object.create(o1)  
   
 o2.a = 1;  
   
 // o2.b nasconde o1.b  
 o2.b = 2;  
   
 // stampa true  
 console.log(o2.hasOwnProperty('a'));  
   
 //false  
 console.log(o2.hasOwnProperty('c'))  
   
 // stampa 4  
 console.log(o2.c);  

Anche le funzioni possono essere ovviamente definite nel prototipo e dunque ereditate

 var o = {  
  a: 2,  
  m: function(b){  
   return this.a + 1;  
  }  
 };  
   
 console.log(o.m()); // 3  
    
 // Quando chiamiamo o.m, in questo caso, 'this' si riferisce ad o  
   
 var p = Object.create(o);  
 // p è un oggetto che eredita da o  
   
 p.a = 12; // crea una own property 'a' su p  
 console.log(p.m()); // 13  
 // quando si invoca p.m, 'this' si riferisce a p.  

Riepilogando, ecco i diversi modi di costruire gli oggetti con le rispettive catene di prototipi

 var o = {a: 1};  
   
 // L'oggetto o ha Object.prototype come suo prototipo  
 // o non ha alcuna proprietà chiamata 'hasOwnProperty'  
 // hasOwnProperty è una proprietà posseduta of Object.prototype. 
 // Dunque o eredita hasOwnProperty da Object.prototype  
 // Object.prototype ha null come suo prototipo.  
 // o ---> Object.prototype ---> null  
   
 var a = ["ciccio", "puccio", "nicolino"];  
   
 // I vettori ereditano da Array.prototype (che ha metodi come indexOf, forEach, etc.)  
 // La catena dei prototipi di a è la seguente  
 // a ---> Array.prototype ---> Object.prototype ---> null  
   
 function f(){  
  return 2;  
 }  
   
 // Le funzioni ereditano fa Function.prototype (che ha metodi come call,   
 // bind, etc.)  
 // La catena dei prototipi di f è la seguente  
 // f ---> Function.prototype ---> Object.prototype ---> null  
   
 // Se usiamo una funzione costruttore  
 function Biblioteca() {  
  this.libri = [];  
 }  
   
 Biblioteca.prototype = {  
  aggiungiLibro: function(libro){  
   this.libri.push(libro);  
  }  
 };  
   
 var b = new Biblioteca();  
 // b è un oggetto che ha proprietà 'libri'   
 // Il prototipo di b è il valore di Biblioteca.prototype dopo   
 // l'invocazione di new Biblioteca().  

Quando dunque accediamo ad una proprietà di un oggetto, se la proprietà non è presente nell'oggetto stesso, viene risalita la catena dei prototipi fino ad arrivare a Object.prototype che ha prototipo null.

E' opportuno evitare di avere catene troppo lunghe per questioni di performance.

Alla prox.
Ivan

Nessun commento:

Posta un commento