0

I've got a little factory pattern example I'm playing with that works fine and gives me a way to create related objects with a generic interface:

 $(document).ready(function () {
            function Car(options) {
                this.color = options.color || 'unknown',
                this.name = options.carName || 'unknown',
                this.doors = options.doors || 4;
            }
            function Truck(options) {
                this.color = options.color || 'unknown',
                this.name = options.name || 'unknow',
                this.doors = options.doors || 2;
            }
            function VehicleFactory() { };
            VehicleFactory.prototype.createVehicle = function (options) {
                if (options.vehicleType === 'car') {
                    return new Car(options);
                }
                else {
                    return new Truck(options);
                }
            }
            var factory = new VehicleFactory();
            var car = factory.createVehicle({
                vehicleType: 'car',
                name: 'bill',
                doors: 2
            });
            console.log(car instanceof Car);//true
            var truck = factory.createVehicle({
                vehicleType: 'truck',
                doors: 3

            });
            //checks to make sure that objects are of the right type
            console.log('truck is an instance of Car: ' + (truck instanceof Car)); //false
            console.log('truck is an instace of Truck: ' + (truck instanceof Truck)); //true
            console.log(truck);
        });

Coming from C# this looks familiar enough and it easy for me to grok. However, I also tend to try to stand on the shoulders of giants and Doug Crockford said no to new.
How could I refactor this code to use Object.create instead of new. Does it REALLY matter to the average person, or does it only matter because the upper echelon says it does?

wootscootinboogie
  • 8,461
  • 33
  • 112
  • 197
  • 1
    Maybe a link to Crockford's comments would help us interpret them in context. – Mike Samuel Oct 24 '13 at 18:48
  • @MikeSamuel this was in a three-part series he did with each video being about an hour long, I'll try to see if I can find a more prudent resource. – wootscootinboogie Oct 24 '13 at 18:49
  • 1
    it wasn't a total avoidance of the new keyword. `Object.create` allows for inheritance in JS (ECMA 5). Using new to create a parent object only allows a reference to that object within the class, it doesn't inherit from it per-se. – David Barker Oct 24 '13 at 18:51
  • Related question: http://stackoverflow.com/questions/383402/is-javascript-s-new-keyword-considered-harmful – Sam Oct 24 '13 at 18:51

1 Answers1

2

How could I refactor this code to use Object.create instead of new?

return new Car(options);

is equivalent (for non-host constructors, and modulo non-object returns) to

var newCar = Object.create(Car.prototype);
return Car.call(newCar, options) || newCar;

which creates an object, and then invokes Car to initialize it.

You could further refactor Car to take an unfinished car to initialize instead of modifying this:

function initializeCar(car, options) {
  car.color = options.color || "red";
  ...
  return car;
}

and then your object creation and initialization code would be

return initializeCar(Object.create(protoCar), options);

but I don't know if any of this is addressing Crockford's main concerns.


Finally putting createVehicle on VehicleFactory.prototype doesn't seem to get you anything. Why

VehicleFactory.prototype.createVehicle = ...

?

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • And allows Car to inherit the prototype and namespace of the original class... good answer. – David Barker Oct 24 '13 at 18:52
  • @Mike could you tell me why that why I refactor out my `return new Car(options)` to your `return.Car.call...` that the line ` console.log('Car is instance of car: ' + (car instanceof Car)); //old way fired true, not it's false ` is now false? – wootscootinboogie Oct 24 '13 at 18:54
  • Unless you're using an implementation of `Object.create` that is non-standard, it should work the same w.r.t `instanceof`. – Mike Samuel Oct 24 '13 at 18:56
  • wrt? this seems like some jargon I need to know :) – wootscootinboogie Oct 24 '13 at 18:56
  • @MikeSamuel I forgot that you could pass arguments to Object.create, good answer. – wootscootinboogie Oct 24 '13 at 18:58
  • @wootscootinboogie, Please see my edits. I was wrong. My "equivalent" code was dropping the newly created object on the floor. – Mike Samuel Oct 24 '13 at 19:00
  • @Mike I put createVehicle on the prototype of VehicleFactory to simulate an interface, so the createVehicle method knows which object to instantiate is encapsulated in the parameters passed to the function. I'm no expert and I'd like to see another way of doing it if you don't mind. – wootscootinboogie Oct 24 '13 at 19:04