2010-06-07 17 views
5

Sto provando a definire una classe javascript con una proprietà array e la relativa sottoclasse. Il problema è che tutte le istanze della sottoclasse in qualche modo "condividere" la proprietà di matrice:Ereditarietà e matrici Javascript

// class Test 
function Test() { 
    this.array = []; 
    this.number = 0; 
} 

Test.prototype.push = function() { 
    this.array.push('hello'); 
    this.number = 100; 
} 

// class Test2 : Test 
function Test2() { 
} 

Test2.prototype = new Test(); 

var a = new Test2(); 
a.push(); // push 'hello' into a.array 

var b = new Test2(); 
alert(b.number); // b.number is 0 - that's OK 
alert(b.array); // but b.array is containing 'hello' instead of being empty. why? 

Come potete vedere non ho questo problema con tipi di dati primitivi ... Qualche suggerimento?

+1

Vedi http://stackoverflow.com/questions/1485824/javascript -inheritance-objects-dichiarato-in-costruttore-sono-condivisi-tra-inst –

risposta

1

L'unica cosa che posso pensare è che gli array sono riferimenti condivisi. Ci dovrebbe essere una soluzione ovvia dato che questo tipo di codice OOP classico è implementato tutto il tempo in Javascript.

4

Se si scrive Test2.prototype = new Test(), si crea una singola istanza Test, con una singola istanza di matrice, che è condivisa da ogni istanza Test2.

Pertanto, tutte le istanze Test2 condividono lo stesso array.

È possibile risolvere questo problema chiamando il costruttore di base Test dal costruttore Test2, che creerà una nuova istanza di matrice per ogni istanza Test2.

Ad esempio:

function Test2() { 
    Test.call(this); 
} 
3

altro, non elegante, alternativa è quella di spostare il codice di inizializzazione dal costruttore ad un metodo e chiamare da entrambi i costruttori:

// class Test 
function Test() { 
    this.init(); 
} 

Test.prototype.init = function() { 
    this.array = []; 
    this.number = 0; 
}; 

Test.prototype.push = function() { 
    this.array.push('hello'); 
    this.number = 100; 
}; 

// class Test2 : Test 
function Test2() { 
    this.init(); 
} 

Test2.prototype = new Test(); 
+0

+1 per chiarezza. – jvenema

1

JavaScript non ha un sistema ereditario classico, ha un sistema di eredità prototipale. Quindi in JavaScript tecnicamente non esiste il concetto di "Classe".

Gli oggetti ereditano da altri oggetti (il cosiddetto oggetto prototipo), non classi astratte. Una grande conseguenza di ciò è che se diversi oggetti condividono lo stesso prototipo e uno di questi oggetti modifica un attributo definito nel prototipo, tale modifica è immediatamente effettiva per tutti gli altri oggetti.

Provare ad usare l'ereditarietà di JavaScript come se fosse basato su classi di solito causa grossi grattacapi, perché questo tipo di problemi si verifica sempre.

So che questo in realtà non risponde alle vostre domande particolari, ma ad un livello elevato vi consiglio di abbracciare l'ereditarietà prototipale invece di cercare di usare "pseudo-classi". Anche se all'inizio sembra strano, il tuo codice sarà molto più affidabile e non perderai tempo a cercare di capire bug strani come questo, causati da una strana catena di prototipi.

Guarda questo video in cui Douglas Crockford spiega l'ereditarietà, è disponibile online nel sito Web Yahoo UI Theater. E 'cambiato il modo in cui ho programmato in JavaScript :)

http://video.yahoo.com/watch/111585/1027823 (link alla prima parte)

http://developer.yahoo.com/yui/theater/ (per tutti i video)