I have the following JavaScript files:
src/js/classes/Lexus.js:
import {Car} from 'src/js/classes/Car';
export class Lexus extends Car {
constructor() {
super("Lexus");
}
}
src/js/classes/Mercedes.js:
import {Car} from 'src/js/classes/Car';
export class Mercedes extends Car {
constructor() {
super("Mercedes");
}
}
src/js/classes/Car.js:
import {Lexus} from 'src/js/classes/Lexus'; //either of those imports works, but not both!
import {Mercedes} from 'src/js/classes/Mercedes'; //either of those imports works, but not both!
export class Car {
constructor(make) {
this.make = make;
}
static factory(msg) {
switch(msg) {
case "Lexus":
return new Lexus();
case "Mercedes":
return new Mercedes();
}
}
}
and app.js:
import {Lexus} from 'src/js/classes/Lexus';
import {Mercedes} from 'src/js/classes/Mercedes';
import {Car} from 'src/js/classes/Car';
var car = Car.factory("Lexus");
console.log(car);
The interesting thing, if I import either Lexus
or Mercedes
to the Car class and call the factory method in app.js - everything works fine; however if I import both Lexus
and Mercedes
to the Car class I got an error:
Super expression must either be null or a function, not undefined
What do I miss ?
The ES6 JavaScript supports Object-Oriented programming components such as Object, Class and Methods. Further in Classes we can implement inheritance to make child inherits all methods of Parent Class. This can be done using the extends and super keywords. We use the extends keyword to implement the inheritance in ES6.
ES6 comes to your rescue with the concept of Modules. A module organizes a related set of JavaScript code. A module can contain variables and functions. A module is nothing more than a chunk of JavaScript code written in a file. By default, variables and functions of a module are not available for use.
Using class inheritance, a class can inherit all the methods and properties of another class. Inheritance is a useful feature that allows code reusability.
The most important difference between class- and prototype-based inheritance is that a class defines a type which can be instantiated at runtime, whereas a prototype is itself an object instance.
Typically, you want to not have circular dependencies like this. Circular dependencies at the best of times, break everything and don't compile (or transpile). Circular dependencies at the worst of times, cause merge and versioning conflicts, cause code that's really hard to discern, look like they're working just fine, until they stop, with some terrible bug caused by some terrible state assumptions.
Your solution (if you are dead-set on this form of inheritance) is going to be to extract Car
into its own file/class, which can be imported separately, and to have the Factory be separate from the class.
Which, in English makes complete sense.
Cars don't construct Lexuses (Lexi?).
Additionally, if you did want to keep this (not a great idea), then you should have a register method, not a hard-coded solution, whereby you register "Lexus" and the function which makes a new Lexus.
import Car from "./car";
class Lexus extends Car {
constructor () {
super("Lexus");
}
// starting to look like a bad idea
static make () {
return Car.make("Lexus");
}
// starting to look worse
static register () {
/* this register method does nothing, so that Lexus can't make other cars... */
}
}
Car.register("Lexus", () => new Lexus());
export default Lexus;
It gets worse, but this is already plenty bad.
If you go the other route:
// carfactory.js
const carTypes = new Map();
class CarFactory {
static register (name, implementation) {
carTypes.set(name, implementation);
return CarFactory;
}
static make (name) {
const makeCar = carTypes.get(name);
return makeCar();
}
register (name, implementation) {
CarFactory.register(name, implementation);
return this;
}
make (name) { return CarFactory.make(name); }
}
export default CarFactory;
// index.js
import Car from "./classes/car";
import Lexus from "./classes/lexus";
import CarFactory from "./factories/car";
CarFactory
.register("Lexus", () => new Lexus())
.register("Bentley", () => new Bentley());
init( CarFactory );
function init (Car) {
const lexus = Car.make("Lexus");
}
Now, no classes need to know about things they shouldn't have to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With