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
*/
Mathieu Guindon
75.5k18 gold badges194 silver badges467 bronze badges
asked Aug 21, 2015 at 21:56
\$\endgroup\$
2
  • \$\begingroup\$ @Mat's Mug - someone answered, but it's disappeared; could you enlighten me please. \$\endgroup\$ Commented Aug 22, 2015 at 4:14
  • 1
    \$\begingroup\$ Why don't you use more common function Foo() {}; Foo.prototype.bar = function() {}; var foo = new Foo();? \$\endgroup\$ Commented Dec 2, 2015 at 21:14

1 Answer 1

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! :)

answered Jan 6, 2016 at 2:21
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.