2016-04-17 34 views
7

Desidero creare istanze univoche di un set di automobili che persone diverse possono contenere. Le auto avranno specifiche di base simili, ma alcune delle loro proprietà e metodi varieranno.Come si crea un'istanza di un'istanza in JavaScript

Il problema che ho è che non riesco a capire come dovrebbe funzionare. Come gestisci o crea istanze di istanze in JavaScript?

var Car = function(make, country) { 
    this.make = make; 
    this.country = country; 
}; 

var Ferrari = new Car('Ferrari', 'Italy'); 

var fred = new Person() {}; 
var fred.cars['Ferrari'] = new Ferrari(1200, 300000); 

Ciò causa questo errore, per ovvi motivi. Sono consapevole che non è un costruttore (vedi sotto).

Uncaught TypeError: Ferrari is not a constructor 

Quello che sto cercando è qualcosa di simile. Ogni diversa istanza di una Ferrari avrà un prezzo e un miliardo diversi.

var Ferrari = function(currentPrice, miles) } 
    this.currentPrice = currentPrice; 
    this.miles = miles; 
    // this is an instance of car, aka it needs the result of this: 
    // new Car('Ferrari', 'Italy'); 

}; 

La Ferrari di Fred è un'istanza della Ferrari, che è un'istanza di Car. Il problema è che non riesco a pensare a un modo per fare un costruttore a costruire un costruttore. C'è un modo per farlo, o sto solo facendo questo nel modo sbagliato?

Altre note:

So che potrei essenzialmente solo rendere ogni tipo di auto un oggetto JSON-come statico e poi fare le istanze di quel e aggiungere nuovi valori univoci. Tuttavia, mi piacerebbe essere in grado di mantenere l'auto come un costruttore in modo da poter facilmente fare di più quando ne ho bisogno.

Mi manca chiaramente qualche comprensione di OOP o JavaScript qui, ma sarebbe bello se qualcuno potesse indicarmi la giusta direzione.

+1

'Ferrari' dovrebbe essere una sottoclasse, non un'istanza; dovrebbe "estende l'auto". – jonrsharpe

+0

Per chiunque fosse confuso come me, c'è una buona pagina su MDN che spiega come creare una gerarchia di oggetti in JS rispetto alle lingue basate su classi: https://developer.mozilla.org/en/docs/ Web/JavaScript/Guida/Dettagli_della_Oggetto_Modello – jamcd

risposta

5

Quello che stai cercando è un costruttore derivato e prototipo associato, a volte chiamato una sottoclasse .

Nel vecchio stile ES5 Sembra che questo:

var Car = function(make, country) { 
    this.make = make; 
    this.country = country; 
}; 
var Ferrari = function(currentPrice, miles) { 
    Car.call(this, "Ferrari", "Italy"); 
    this.currentPrice = currentPrice; 
    this.miles = miles; 
}; 
Ferrari.prototype = Object.create(Car.prototype); 
Ferrari.prototype.constructor = Ferrari; 

come funziona:

  • Ferrari è una funzione di costruzione che, quando viene chiamato, chiamate Car con this riferendosi alla nuova istanza, insieme con gli argomenti Car esigenze. Car fa le sue cose impostando queste proprietà sull'istanza. Quindi continuiamo con il codice Ferrari, che accetta gli argomenti passati e (in quanto sopra) li ricorda come proprietà.

  • Facciamo in modo che l'oggetto che verrà assegnato alle istanze da new Ferrari (che è tratto da Ferrari.prototype) utilizza Car.prototype come oggetto prototipo, in modo che se si aggiungono le cose a Car.prototype, saranno presenti sul Ferrari s come bene.

  • Ci assicuriamo che la proprietà standard constructor su Ferrari.prototype si riferisca a Ferrari.

Piuttosto più bello in ES2015 (che è possibile utilizzare oggi via transpilation, come ad esempio con strumenti come Babel):

class Car { 
    constructor(make, country) { 
     this.make = make; 
     this.country = country; 
    } 
} 
class Ferrari extends Car { 
    constructor(currentPrice, miles) { 
     super("Ferrari", "Italy"); 
     this.currentPrice = currentPrice; 
     this.miles = miles; 
    } 
} 
+0

@ Jordão: Grazie! Fisso. –

+0

L'esempio ES2015 è simile a quello che ho visto in PHP, ma non è riuscito a trovare una funzionalità simile in Javascript. Grazie! – jamcd

+1

Si ricorda inoltre che il modello di classe dell'OP è rotto: le proprietà 'price' e' miles' appartengono alla classe base – Alnitak

-1

Se si desidera che i Car casi ad essere costruttori, Car deve tornare un costruttore .

Il problema è che quindi erediterà da Function.prototype anziché da Car.prototype. Se questo è indesiderabile, utilizzare Object.setProtetypeOf per risolvere il problema:

function Person() { 
    this.cars = {}; 
} 
function Car(make, country) { 
    var instance = function(currentPrice, miles) { 
    this.currentPrice = currentPrice; 
    this.miles = miles; 
    }; 
    instance.make = make; 
    instance.country = country; 
    Object.setPrototypeOf(instance, Car.prototype); // slow!! 
    return instance; 
} 
var Ferrari = new Car('Ferrari', 'Italy'); 
var fred = new Person(); 
fred.cars.ferrari = new Ferrari(1200, 300000); 

In alternativa, è possibile aggiungere un metodo che verrà utilizzato per "istanziare" le istanze.

function Person() { 
    this.cars = {}; 
} 
function Car(make, country) { 
    this.make = make; 
    this.country = country; 
} 
Car.prototype.instantiate = function(currentPrice, miles) { 
    var instance = Object.create(this); 
    instance.currentPrice = currentPrice; 
    instance.miles = miles; 
    return instance; 
}; 
var ferrari = new Car('Ferrari', 'Italy'); 
var fred = new Person(); 
fred.cars.ferrari = ferrari.instantiate(1200, 300000); 
+0

Grazie per aver fornito un'alternativa. Se non ti dispiace che me lo chieda, c'è qualche vantaggio nell'usare questo invece del metodo "call"? – jamcd

+0

@jamcd Sono approcci diversi. 'call' viene usato durante la sottoclasse, per chiamare il super costruttore dall'estensione. Ma tu vuoi istanziare istanze, non un subcostruttore. Quindi il super costruttore è già stato chiamato per creare l'istanza che vuoi istanziare, e quindi non c'è motivo di chiamarla di nuovo. Il vantaggio degli approcci che ho fornito rispetto alla sottoclasse è che non è necessario conoscere i nomi delle auto (ad esempio Ferrari) in anticipo. Dalla domanda, ho capito che questo era ciò che volevi, non sottoclasse. – Oriol