Sto imparando il JavaScript su un libro (learning Javascript di Shelley Powers) che, purtroppo, ogni tanto tratta in modo troppo superficiale alcuni argomenti.... fornendo una soluzione veloce senza analizzare le motivazioni che stanno dietro ad un certo stile di programmazione
Conosco abbastanza bene la programmazione ad oggetti (quella con classi esplicite) è ho ben compreso l'uso di prototype e la precedenza che hanno i metodi privilegiati dei suo confronti
però mi sfugge la motivazione di un modo, di ereditare le funzionalità di un altro oggetto, che era presentato come il più naturale:
Codice:
function tune(title,type) {
this.title = title;
this.type = type;
this.getTitle=function() {
return "Song: " + this.title + " Type: " + this.type;
}
}
function artist_tune(title,type,artist) {
this.artist = artist;
this.toString("Artist is " + artist);
tune.apply(this,arguments);
this.toString = function () {
return "Artist: " + this.artist + " " + this.getTitle();
}
}
artist_tune.prototype = new tune();
Questo comprende sia la chiamata del costruttore della superclasse (attraverso l'uso di apply() o call()) che l'assegnamento di una istanza della superclasse all'oggetto prototype della sottoclasse
ma questa cosa non ha senso, ovvero secondo me è inutile inizializziare prototype in questo caso, l'assegnamento che avvenga o meno non fa alcuna differenza
ho preparato un piccolo esempio dove analizzo tutti i casi possibili con le evidenti differenze
B, C e D sono tutti oggetti che specializzano A ma lo fanno in modi diversi, nonostante ciò appaiono esternamente con le medesime capacità di accesso ai membri pubblici della superclasse
Codice:
function A(){
var x="valore di default";
this.set=function(v){
x=v
};
this.get=function(){
return x;
}
}
function B(){}
function C(){A.apply(this);}
function D(){A.apply(this);}
B.prototype=new A;
D.prototype=new A;
a1=new A();
a1.set("sono a1");
alert(a1.get()); // "sono a1"
a2=new A();
alert(a2.get()) // "valore di default"
b1=new B();
b1.set("sono b1");
alert(b1.get()); // "sono b1"
b2=new B();
alert(b2.get()) // "sono b1"
c1=new C();
c1.set("sono c1");
alert(c1.get()); // "sono c1"
c2=new C();
alert(c2.get()) // "valore di default"
d1=new D();
d1.set("sono d1");
alert(d1.get()); // "sono d1"
d2=new D();
alert(d2.get()) // "valore di default"
Nel primo caso l'oggetto B si limita a inizializzare prototype, questo comporta la "condivisione" delle variabili private della superclasse tra due istanze diverse di B; è un comportamento di cui non colgo l'uso pratico, se sapete perchè e che senso ha illuminatemi
Nel secondo caso (oggetto C) la modalità è quella classica, si usa un costruttore e il comportamento ottenuto è tipico di qualsiasi linguaggio OOP che io conosco
Nel terzo caso (oggetto D) avviene la stessa cosa dell'esempio che ha suscitato la mia curiosità, una combinazione di costruttore e inizializzazione di prototype e non ne capisco il motivo, il comportamento sembra sia identico a quello dell'oggetto C
L'unica cosa che cambia è la possibilità di accede attraverso prototype ai metodi della superclasse ma è inutile, ogni cambiamento viene ignorato perchè javascript cerca i metodi prima tra quelli privilegiati (definiti all'interno della funzione "madre")
Che senso ha tutto ciò? Quando utilizzare una delle seguenti combinazioni al posto di altre? C e D possono considerarsi equivalenti?
Un grazie a chi avrà la pazienza di legger tutto quello che ho scritto e mi aiuterà a capire