7
\$\begingroup\$

I wanted an easy way to augment objects, by adding functionality from any other object(s). More importantly, I needed a way to augment the object from multiple sources in a clean one-line solution.

The inheritance is done with this:

function extend(proto, args){
    this[proto.id] = Object.create(proto);
    proto.constructor.call(this[proto.id], args);
}

extend.call(this, vehicle, args); // one-liner

I can invoke as many objects as needed; with this pattern it's easy to swap and change the prototype chain, so I could just put the above extend code in the vehicle object, if that's where I want augmentation.

It's now easy to create a car by pulling in whatever you need:

extend.call(this, vehicle, args);
extend.call(this, sunroof, args);
extend.call(this, tyres, args);
extend.call(this, wings, args);
extend.call(this, rocket, args);
etc...

Questions:

  • Plausibility: is it flawed in some way?
  • Optimisation: can I enhance the pattern?
  • clunky: I had to create an id property for each object, so the extend function knows how to create a property on the executing context. It seems like a hack. Is there a way to get a prototype name from a named constructor?

var manufacturer = {
    id:'manufacturer',
    constructor : function (args) {
        this.boss = args.boss || 'Bernie Ecclestone';
      this.country = args.country || 'UK';    
        return this;
    }
};

var vehicle = {
    id:'vehicle',
    constructor : function (args) {
        this.colour = args.colour || 'blue';
      this.wheels = args.wheels || 2;     
        extend.call(this, manufacturer, args);
        return this;
    }
};

var driver = {
    id:'driver',
    constructor : function (args) {
        this.name = args.name || 'John';
        return this;
    },
    info : function () { console.log(this.name); }
};

var engine = {
    id:'engine',
    constructor : function (args) {
        this.type = args.type || 'V6';
        this.fuel = args.fuel || 'petrol';
        return this;
    },
    tune : function () { 
        this.type = 'super-charged';
        this.fuel = 'ethanol';
        console.log('Car now ' + this.type + ' with ' + this.fuel); 
    }
};

var car = {
    id:'car',
    constructor : function (args) {       
        extend.call(this, vehicle, args);
      extend.call(this, driver, args); 
        extend.call(this, engine, args);   
        return this;
    },
    info : function () { 
        console.log('boss: ' + this.vehicle.manufacturer.boss);
        console.log('country: ' + this.vehicle.manufacturer.country);
        console.log('driver: ' + this.driver.name);
        console.log('colour: ' + this.vehicle.colour);
      console.log('wheels: ' + this.vehicle.wheels);
      console.log('type: '   + this.engine.type);
      console.log('fuel: '   + this.engine.fuel);
        console.log('\n');
  }
};

function extend(proto, args){
  this[proto.id] = Object.create(proto);
  proto.constructor.call(this[proto.id], args);
}

var ferrari = Object.create(car).constructor({
    boss: 'Maurizio Arrivabene',
    country:'Italy',
    name: 'Steve', 
    colour: 'red', 
    wheels: 4, 
    type:'100cc', 
    fuel:'diesel'
});

var lotus = Object.create(car).constructor({
    name: 'Jenson Button'
});

var mclaren = Object.create(car).constructor({
  type:'hybrid',
    fuel:'battery/petrol'
});

ferrari.engine.tune();
ferrari.info();
/*
Car now super-charged with ethanol
boss: Maurizio Arrivabene
country: Italy
driver: Steve
colour: red
wheels: 4
type: super-charged
fuel: ethanol
*/

lotus.info();
/*
boss: Bernie Ecclestone
country: UK
driver: Jenson Button
colour: blue
wheels: 2
type: V6
fuel: petrol
*/

mclaren.info();
/*
boss: Bernie Ecclestone
country: UK
driver: John
colour: blue
wheels: 2
type: hybrid
fuel: battery/petrol
*/
\$\endgroup\$
2
  • \$\begingroup\$ @Mat's Mug - someone answered, but it's disappeared; could you enlighten me please. \$\endgroup\$ – Data Aug 22 '15 at 4:14
  • 1
    \$\begingroup\$ Why don't you use more common function Foo() {}; Foo.prototype.bar = function() {}; var foo = new Foo();? \$\endgroup\$ – Pavlo Dec 2 '15 at 21:14
2
\$\begingroup\$

Very interesting concept, I could see this turning into a "Pimp my Ride" game. A few things before this is sent off to gamers:

OOP

It seems like you've kind of misunderstood what OOP is about. As it is, you have a lot of variables (not objects) which then are smushed together into a final concept (the car).

If you want this to be more OOP oriented, here's some things I suggest:

Get rid of all the variables, except car. Keep this, as it will represent your "object". Instead of the manufacturer having his own variable (who knows, maybe some car will be custom built or have various manufacturers), use getters and setters to define a property of car. Picture it this way:

Car object {
    Initialize the object here

    get manufacturer() {

    }
    set manufacturer(string or array or object) {

    }
}

Now your code might get a big here if you implement each detail with a getter and setter. Sometimes you can manage this, other times not, which then you might break things apart: have the manufacturer get/set in an engine object, and the car will only have the get/set for engines.

Like one of the comments said, you should research object prototyping. For a fresh start on JavaScript programming in an object oriented style, read Mozilla's documentation.

Misc.

I'm not convinced having a Ferrari variable and a lotus variable are the best way to accomplish creating cars. I suggest a new object, maybe CarColection or Garage and create/retrieve/store/pimp your cars their. It will allow for later changes, or dynamic modification of the cars.

Purely for fun and for homework: add in the ability to specify exhaust, transmission, tires, driving skill, etc. and then compute horsepower/car level. Pretty soon you could challenge cars up against each other in races! :)

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.