Thursday April 24, 2014:

Functional (and Shared) Instantiation

There are four ways to instantiate a function object. Today, we'll discuss the first two: Functional and Functional-Shared Instantiation. I'll write a post about the other two soon..

(edit: My post on prototypal and pseudoclassical instantiation can be found here.)


Functional Instantiation

TL;DR: A function that returns an object where each instance has it's own copy of methods. It's also the only instantiation method that has closures.

Example:

var makeCar = function (color, vin) {  
    var carInstance = {};
    var carVin = vin;

    carInstance.carColor = color;

    carInstance.seeVin = function () {
        console.log('This car\'s VIN is ' + carVin);
    };
    carInstance.engineSound = function () {
        alert('Vroom vrooom!');
    };

    return carInstance;
};

//instance
var car = makeCar('red', 12345);  

The following object is created:

car = {  
    carColor: red,

    seeVin: function () { 
        console.log('This car\'s VIN is ' + carVin);
    },
    engineSound: function () { 
        alert('Vroom vrooom!');
    },
};

Our newly created car instance has it's own methods and properties. If these methods need to be changed, each instance's methods must be changed one by one.

But where did the variable carVin go?

Functional instantiation is the only pattern that has closures. If you'd like a refresher on closures, I'll post a link to a good resource soon (EDIT: here or here). In the meantime, think of a closure as a private variable that only our car instance can access.

car.seeVin(); //12345  

Functional Instantiation:

  • Has private variables in closure
  • Easy to understand
  • Since each method has it's own methods, this method can be inefficient on a large scale
  • Difficult to update methods

Functional-Shared Instantiation

TL;DR: A function that returns an object where each instance's methods reference another object's methods.

Example:

var makeCar = function (color, vin) {  
    var carInstance = {};

    carInstance._carVin = vin;
    carInstance.carColor = color;

    extend(carInstance, carMethods);

    return carInstance;
};

var carMethods = {};

carMethods.seeVin = function () {  
    console.log('This car\'s VIN is ' + this._carVin);
};

carMethods.engineSound = function () {  
    alert('Vroom vrooom!');
};

var extend = function (to, from) {  
    for (var key in from) {
        to[key] = from[key];
    }
};

//instance
var car = makeCar('red', 12345);  

A functional-shared pattern yields this version of our car instance:

car = {  
    _carVin: 12345,
    carColor: red,

    seeVin: function () {
        console.log('This car\'s VIN is ' + _carVin);
    },

    engineSound: function () {
        alert('Vroom vrooom!');
    }
};

Very similar to functional instantiation, except for the inclusion of the _carVin property, which is now accessible since it is no longer stored in a closure. The "_" prefix of this property indicates to other developers that this key/value pair is meant to be private and shouldn't be changed.

The main difference here is that our instance of car, and all subsequent instances, will all share the method definitions of carMethods because they have been extended to the carInstance object in the makeCar function.

If additional methods are added, or existing methods are changed in carMethods, future car instances will be adjusted, but existing cars will not be updated. This is because the methods are extended using references, meaning they are pointing to function definitions.

References

Conclusion:

  • No private variables in closure
  • Depends on using an extend function
  • Difficult to update methods

New blog post for prototypal and pseudoclassical instantiation coming soon...

(edit: My post on prototypal and pseudoclassical instantiation can be found here.)