2015-09-16 14 views
24

Ho incontrato un problema di seguito con JavaScript (ES6)genitore che viene sovrascritto da bambino durante catena costruttore in JavaScript (ES6)

class A{ 
    constructor(){ 
    this.foo(); 
    } 
    foo(){ 
    console.log("foo in A is called"); 
    } 
} 

class B extends A{ 
    constructor(){ 
    super(); 
    this.foo(); 
    } 
    foo(){ 
    console.log("foo in B is called"); 
    } 
} 

quello che mi aspetto è

foo in A is called 
foo in B is called 

ma in realtà si tratta di

foo in B is called 
foo in B is called 

so che posso risolvere questo semplicemente aggiungendo super.foo() in classe funzione foo di B

class B extends A{ 
    constructor(){ 
    super(); 
    this.foo(); 
    } 
    foo(){ 
    super.foo() // add this line 
    console.log("foo in B is called"); 
    } 
} 

Ma immaginare uno scenario simile a questo:

bambino deve sostituire la funzione dei genitori al fine di fare alcuni lavori in più e impedire l'accesso da esterno poter accedere a quella originale.

class B extends A{ 
    constructor(){ 
    super(); 
    this.initBar(); 
    } 
    foo(){ 
    super.foo(); 
    this.bar.run(); //undefined 
    console.log("foo in B is called"); 
    } 
    initBar(){ 
    this.bar.run = function(){ 
     console.log("bar is running"); 
    }; 
    } 
} 

Sembra che this punti ancora da bambino B, mentre la costruzione di genitore A. Ecco perché non riesco a raggiungere il genitore A's foo.

Come faccio a rendere this per chiamare la funzione di versione padre che viene sovrascritta da child durante la catena del costruttore?

Oppure c'è una soluzione migliore quando si tratta di uno scenario come questo?

Modifica

Così, dopo aver letto le risposte, la questione principale diventa -

E 'sconsigliato mettere initialize helpers o setter functions nel costruttore in JavaScript poiché i bambini hanno la possibilità di ignorare loro?

Per chiarire la situazione in modo più chiaro: (scusate per il mio precedente cattivo esempio :()

class A{ 
    constructor(name){ 
    this.setName(name); 
    } 
    setName(name){ 
    this._name = name; 
    } 
} 

class B extends A{ 
    constructor(name){ 
    super(name); 
    this._div = document.createElementById("div"); 
    } 
    setName(name){ 
    super.setName(name); 
    this._div.appendChild(document.createTextNode(name)); 
    } 
} 

new B("foo") 

this._div saranno undefined

questa è una cattiva idea, in quanto bambino sarà in grado di ignorare. la funzione?

class A{ 
    constructor(name){ 
    this.setName(name); // Is it bad? 
    } 
    ... 
} 

Quindi non dovrebbe usare initialize helpers o setter functions a const ruttore come in Java, C++ ...?

Devo chiamare manualmente cose come questa new A().init() per aiutarmi a inizializzare le cose?

+0

* Come faccio a "questo" per chiamare la funzione di versione genitore * - 'super' è l'unico modo. – thefourtheye

+0

Perché il costruttore 'A' chiama' this.foo() '? Non dovrebbe, dovrebbe solo inizializzare l'istanza. – Bergi

+0

Il figlio 'pippo' ha lo scopo di scavalcare l'implementazione genitore nella causa generale, o stai chiedendo più come fare" pippo "ad un helper privato? – loganfsmyth

risposta

9

Sembra che tu stia operando sotto un equivoco che ci sono due oggetti A e B quando sei nel costruttore della classe derivata B. Non è assolutamente il caso. C'è un solo oggetto. Entrambi A e B contribuiscono con proprietà e metodi a quell'unico oggetto.Il valore di this sarà lo stesso nel costruttore per B come è nel costruttore per A durante la creazione di un oggetto della classe B.

la sintassi classe ES6 è solo zucchero rispetto al metodo ES5 di utilizzare prototipi tipi di oggetti e, di fatto, il prototipo è ancora utilizzato sotto le coperte. Pertanto, quando si definisce un metodo foo in una classe derivata come si fa in classe B, si sta ancora assegnando al prototipo e quell'assegnazione sovrascrive qualsiasi metodo con lo stesso nome che potrebbe già esistere sul prototipo proveniente dalla definizione padre . Questo è il motivo per cui this.foo() si riferisce alla versione di classe B foo. Se si desidera raggiungere la versione di classe A di foo, sarà necessario specificarlo manualmente utilizzando super come sembra già sapere.

Per quanto riguarda le vostre domande specifiche:

Sembra che questo punta ancora a bambino B, mentre la costruzione in genitore A. Ecco perché io non riesco a raggiungere pippo madre di A.

figlio B e padre A non sono oggetti separati. C'è un oggetto che sia il riferimento A padre che il riferimento B figlio. i metodi oi costruttori padre A e figlio B vedranno lo stesso identico valore di this.

Come si fa a chiamare la funzione di versione genitore che è stata sostituita dal figlio durante la catena di costruzione ?

Si utilizza super per fare riferimento a metodi padre direttamente come sembra già sapere.

Oppure c'è una soluzione migliore quando si tratta di uno scenario come questo?

super è la soluzione.


Cordiali saluti, questo è un buon discussione sulle classi ES6 tra cui come super lavori: Classes in ECMAScript 6 (final semantics). La sezione 4.4 sembra particolarmente rilevante per la tua domanda/comprensione.

+0

Penso che sia meglio non usare setter nel costruttore genitore come "this.setName (name);" e sarà meglio usare this.name = name; in questo modo quando usi super() non utilizzerai le funzioni di override a cui non sei consapevole. – llioor

Problemi correlati