2009-05-21 11 views
162

Sono nuovo su JavaScript OOP. Puoi spiegare la differenza tra i seguenti blocchi di codice. Ho provato ed entrambi i blocchi funzionano. Qual è la migliore pratica e perché?Informazioni sull'eredità prototipale in JavaScript

Primo blocco:

function Car(name){ 
    this.Name = name; 
} 

Car.prototype.Drive = function(){ 
    document.write("My name is " + this.Name + " and I'm driving. <br />"); 
} 

SuperCar.prototype = new Car(); 
SuperCar.prototype.constructor = SuperCar; 

function SuperCar(name){ 
    Car.call(this, name); 
} 

SuperCar.prototype.Fly = function(){ 
    document.write("My name is " + this.Name + " and I'm flying! <br />"); 
} 

var myCar = new Car("Car"); 
myCar.Drive(); 

var mySuperCar = new SuperCar("SuperCar"); 
mySuperCar.Drive(); 
mySuperCar.Fly(); 

Secondo blocco:

function Car(name){ 
    this.Name = name; 
    this.Drive = function(){ 
     document.write("My name is " + this.Name + " and I'm driving. <br />"); 
    } 
} 

SuperCar.prototype = new Car(); 

function SuperCar(name){ 
    Car.call(this, name); 
    this.Fly = function(){ 
     document.write("My name is " + this.Name + " and I'm flying! <br />"); 
    } 
} 

var myCar = new Car("Car"); 
myCar.Drive(); 

var mySuperCar = new SuperCar("SuperCar"); 
mySuperCar.Drive(); 
mySuperCar.Fly(); 

Perché l'autore aggiungere Drive e Fly metodi utilizzando prototype, ma non li dichiarano come this.Drive metodo all'interno Car di classe e this.Fly nella classe SuperCar?

Perché è necessario impostare SuperCar.prototype.constructor su SuperCar? La proprietà del costruttore è stata sostituita quando è impostato prototype? Ho commentato questa riga e nulla è cambiato.

Perché chiamare il Car.call(this, name); nel costruttore SuperCar? Will non proprietà e metodi di Car essere 'ereditati' quando faccio

var myCar = new Car("Car"); 
+3

Il modo più moderno è quello di utilizzare Object.create () invece di nuovo: http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon

+2

Solo una nota di questo esempio può confondere: "super" in questo caso si riferisce a una macchina volante, mentre "super" in OOP si riferisce normalmente al prototipo/classe genitore. – mikemaccana

+2

Penso che la parte che rende l'eredità prototipica di JavaScript difficile da capire è dove si mescola con un costruttore. Cosa succede se rimuoviamo l'idea del costruttore e della classe e abbiamo solo oggetti. Ogni oggetto è o ereditato dal nulla (null) o da un altro oggetto. Sarà molto più facile da capire, ed è esattamente ciò che fa Object.create(). –

risposta

78

I due blocchi differiscono in modo che nel primo esempio Drive() esisterà una sola volta mentre il secondo approccio Drive() esisterà per istanza (Ogni volta che si esegue la funzione new Car()drive() verrà creato nuovo). O diverso detto il primo utilizza il prototipo per memorizzare la funzione e il secondo il costruttore. La ricerca di funzioni è costruttore e quindi prototipo. Quindi per la tua ricerca di Drive() lo trova indipendentemente se è nel costruttore o nel prototipo. L'utilizzo del prototipo è più efficiente perché solitamente è necessaria una funzione solo una volta per tipo.

La chiamata new in javascript imposta automaticamente il costruttore nel prototipo. Se si sta sovrascrivendo il prototipo, è necessario impostare manualmente il costruttore.

L'ereditarietà in javascript non ha nulla come super. Quindi se hai una sottoclasse, l'unica possibilità di chiamare il super costruttore è il suo nome.

1

non sono sicuro al 100%, ma credo che la differenza è che il secondo esempio duplica semplicemente il contenuto della classe Car in supercar oggetto, mentre il primo collega il prototipo SuperCar alla classe Car, in modo che le modifiche di runtime alla classe Car influiscano anche sulla classe SuperCar.

136

Per aggiungere a Norbert Hartl's answer, SuperCar.prototype.constructor non è necessario, ma alcune persone lo usano come un modo conveniente per ottenere la funzione di costruzione di un oggetto (oggetti SuperCar in questo caso).

Proprio dal primo esempio, Car.call (questo, il nome) è in funzione di costruzione SuperCar perché quando si esegue questa operazione:

var mySuperCar = new SuperCar("SuperCar"); 

Questo è ciò che fa JavaScript:

  1. A viene creato un nuovo oggetto vuoto.
  2. Il prototipo interno dell'oggetto nuovo è impostato su Car.
  3. La funzione di costruzione SuperCar corre.
  4. L'oggetto finito viene restituito e impostare in mySuperCar.

Notate come JavaScript non ha chiamato Car per voi. Essendo i prototipi così come sono, qualsiasi proprietà o metodo che non ti piazzi per SuperCar verrà cercato su Car. A volte questo è buono, ad es. SuperCar non ha un metodo di guida, ma può condividere quello di Car, quindi tutte le SuperCar utilizzeranno lo stesso metodo di guida. Altre volte non vuoi condividere, come ogni SuperCar che ha il proprio Nome. Quindi, come si fa a impostare il nome di ogni SuperCar per la propria cosa? È possibile impostare this.Name all'interno della funzione di costruzione SuperCar:

function SuperCar(name){ 
    this.Name = name; 
} 

Questo funziona, ma aspetta un secondo. Non abbiamo fatto esattamente la stessa cosa nel costruttore di automobili? Non voglio ripeterci. Dal momento che la macchina ha già impostato il nome, chiamiamolo.

function SuperCar(name){ 
    this = Car(name); 
} 

Ops, non si vuole cambiare il particolare riferimento this oggetto. Ricorda i 4 passaggi? Appendi all'oggetto che JavaScript ti ha dato, perché è l'unico modo per mantenere il prezioso collegamento del prototipo interno tra il tuo oggetto SuperCar e Car. Quindi, come possiamo impostare il nome, senza ripetere noi stessi e senza buttare via il nostro oggetto SuperCar fresco JavaScript speso così tanto sforzo speciale per prepararsi per noi?

due cose. Uno: il significato di this è flessibile. Due: l'auto è una funzione. È possibile chiamare la macchina, non con un oggetto nuovo e originale, ma con, ad esempio, un oggetto SuperCar. Questo ci dà la soluzione finale, che fa parte del primo esempio nella tua domanda:

function SuperCar(name){ 
    Car.call(this, name); 
} 

Come una funzione, auto è consentito ad essere invocate con della funzione call method, che cambia il significato di this all'interno Car al Istanza di SuperCar che stiamo sviluppando. Presto! Ora ogni SuperCar ottiene la propria proprietà Name.

Per concludere, Car.call(this, name) nel costruttore SuperCar conferisce a ciascun nuovo oggetto SuperCar la propria proprietà Nome univoca, ma senza duplicare il codice già presente in Car.

I prototipi non sono spaventosi dopo averli capiti, ma non assomigliano affatto al classico modello OOP di classe/ereditarietà. Ho scritto un articolo su the prototypes concept in JavaScript. È scritto per un motore di gioco che utilizza JavaScript, ma è lo stesso motore JavaScript utilizzato da Firefox, quindi dovrebbe essere pertinente. Spero che questo ti aiuti.

+4

"SuperCar.prototype.constructor" è necessario se si desidera ' Object.getPrototypeOf' che emula nei motori legacy per funzionare – Raynos

+3

Il collegamento corrente al "concetto di prototipi in Javascript" è rotto. C'è un altro posto in cui posso leggere questo articolo? – shockawave123

8

Norbert, si dovrebbe notare che il vostro primo esempio è più o meno quello che Douglas Crockford chiama eredità pseudoclassical. cose qualcosa di nota di questo:

  1. Potrai chiamare il costruttore auto due volte, una dalla linea SuperCar.prototype = new Car() e l'altro dal "costruttore rubare" linea Car.call (questo .. È possibile creare un metodo di supporto per ereditare invece i prototipi e il costruttore di auto dovrà essere eseguito solo una volta rendendo l'installazione più efficiente
  2. La linea SuperCar.prototype.constructor = SuperCar consentirà di utilizzare instanceof per identificare il costruttore. Alcune persone vogliono che gli altri evitino di usare l'istanza di
  3. I vars di riferimento come: var arr = ['one', 'two'] quando definiti sul super (ad esempio Car) verranno condivisi da TUTTE le istanze, ovvero inst1.arr. pu sh ['three'], inst2.arr.push ['four'], ecc., verranno visualizzati per tutte le istanze!Essenzialmente, comportamento statico che probabilmente non vuoi.
  4. Il secondo blocco definisce il metodo di volo nel costruttore. Ciò significa che per ogni volta che viene chiamato, verrà creato un "oggetto metodo". Meglio usare un prototipo per i metodi! Puoi comunque mantenerlo nel costruttore se vuoi - devi solo proteggerti in modo che tu in realtà solo inizializzi il prototipo letterale una volta (pseudo): if (SuperCar.prototype.myMethod! = 'Function') ... quindi definisci il tuo prototipo letterale.
  5. 'Perché chiamare Car.call (questo, nome) ....': Non ho il tempo di guardare attentamente il tuo codice, quindi potrei sbagliarmi, ma di solito è così che ogni istanza può mantenere il suo stato per risolvere il problema del comportamento "statico" del concatenamento del prototipo che ho descritto sopra.

Infine, vorrei ricordare che ho diversi esempi di codice JavaScript TDD eredità che lavora qui: TDD JavaScript Inheritance Code and Essay Mi piacerebbe ricevere i tuoi commenti come spero di migliorarlo e tenerlo open source . L'obiettivo è quello di aiutare i programmatori classici a familiarizzare rapidamente con JavaScript e integrare lo studio sia dei libri di Crockford che di Zakas.

+1

Ho incontrato il punto (1) prima di adesso. Ho scoperto che se non avessi usato la nuova parola chiave e usato solo Superclass.call (questo) (quindi SuperCar = {Car.call (this);}; SuperCar.prototype = Car;) che sembrava funzionare. C'è una ragione per non farlo? (ci scusiamo per il necro) – obie

+0

Provenendo da * classici * linguaggi OOP, ho sempre trovato * strano * la necessità di creare una 'nuova * istanza * solo * per riempire la catena del prototipo – superjos

+0

Bel libro. Dovresti notare che il link nella parte superiore della pagina di github è rotto, sebbene, naturalmente, possa essere trovato nei contenuti. –

0
function abc() { 
} 

metodi prototipi e struttura ricavata per la funzione abc

abc.prototype.testProperty = 'Hi, I am prototype property'; 
abc.prototype.testMethod = function() { 
    alert('Hi i am prototype method') 
} 

Creazione di nuove istanze per la funzione abc

var objx = new abc(); 

console.log(objx.testProperty); // will display Hi, I am prototype property 
objx.testMethod();// alert Hi i am prototype method 

var objy = new abc(); 

console.log(objy.testProperty); //will display Hi, I am prototype property 
objy.testProperty = Hi, I am over-ridden prototype property 

console.log(objy.testProperty); //will display Hi, I am over-ridden prototype property 

http://astutejs.blogspot.in/2015/10/javascript-prototype-is-easy.html

Problemi correlati