Thursday, November 26, 2015

Value type and reference types in JavaScript

There is not a single time where even sesoned developers have not made this mistake some where in the game. Scratch their head long enough until blood oozes out, they relize the folly they had done and bang their head to the table saying "How did I do it?"

Before you go through the cyle long enough, it's good to understand how value-types and reference-types fit in JS world

 

function valueTypesBehavior() {
    var firstStringVar = "Lorem ipsum";
    var firstStringRef = firstStringVar;
    console.log('First String: ' + firstStringVar + '\nRefernce: ' + firstStringRef);

    firstStringVar = "some other string";
    console.log('First String: ' + firstStringVar + '\nRefernce: ' + firstStringRef);
};

function referenceTypesBehavior() {
    var personVar = {
        firstName: "James",
        lastName: "Bond"
    };
    var personVarRef = personVar;
    console.log('Person object - FirstName:' + personVar.firstName + ', LastName: ' + personVar.lastName);
    console.log('Reference object - FirstName:' + personVarRef.firstName + ', LastName: ' + personVarRef.lastName);

    personVar.firstName = "Sheldon";
    personVar.lastName = "Cooper";
    console.log('Person object - FirstName:' + personVar.firstName + ', LastName: ' + personVar.lastName);
    console.log('Reference object - FirstName:' + personVarRef.firstName + ', LastName: ' + personVarRef.lastName);
};

(function() {
    valueTypesBehavior();
    referenceTypesBehavior();
})();


Output

First String: Lorem ipsum Refernce: Lorem ipsum
First String: some other string Refernce: Lorem ipsum

Person object - FirstName:James, LastName: Bond
Reference object - FirstName:James, LastName: Bond

Person object - FirstName:Sheldon, LastName: Cooper
Reference object - FirstName:Sheldon, LastName: Cooper
Let's create a simple Temperature conversion program to help us build OO approach in JS

End objective
Let's start with an objective. That being a simple function which will convert Celsius to Fahrenheit and vice-versa. We will take it a little further, make the method memoizing method too.

Although there are 2 different ways in JS to build OO solution, we'll take prototype route for this discussion. We'll talk about the other approach, later

Steps to achieve our objective

  • Create a constructor for temperature conversion
  • Add methods, through prototype
  • Invoke those methods


Tough part is how we do the invocation of methods. There are several ways to do it. I have detailed a couple of ways. I prefer keeping things simple and unit testable. As long as the code is less cluttered, it is easier for us to build solutions on top of it. Lets see how

We could make a smaller change to doConversion method. We can make it accept a string parameter and based on the string we could invoke appropriate method. But that's more error prone and leads to lot of code building/maintenance. Sample of that is mentioned below. I prefer to stay away from it.

SimpleConversion.html
       

function TempratureConversionStore(temprature, conversionStore) {
    this.temprature = temprature;
    this.conversionStore = conversionStore;
}

TempratureConversionStore.prototype.celsiusToFahrenheit = function() {
    return (this.temprature * (9 / 5) + 32);
};

TempratureConversionStore.prototype.fahrenheitToCelsius = function() {
    return this.temprature * 1.8 + 32;
};

TempratureConversionStore.prototype.doConversion = function(fn) {
    var result = 0;
    result = fn.call(this);
    return result;
};

// public/global methods
var temperatureFromUserInput = function() {
    var userInput = prompt("Enter celsius", "50");
    var tempInC = 0;
    try {
        tempInC = parseFloat(userInput);
        if (isNaN(tempInC)) {
            throw "Not a Number";
        };
    } catch (e) {
        console.log(e);
        tempInC = 0;
    } finally {
        return tempInC;
    }
};

var doConversion = function() {
    var userInput = temperatureFromUserInput();
    var conversionStore = new TempratureConversionStore(userInput, null);
    console.log('Result:' + conversionStore.doConversion(conversionStore.celsiusToFahrenheit));
};
       
 

I'd not call this a bad solution, but will certainly nopt hesitate to state that it's a maintenance affair

Less preferred solution

       

TempratureConversionStore.prototype.doConversion = function(fnString) {
    var result = 0;
    switch (fnString) {
        case "CtoF":
            result = this.centigrateToFarenheit();
            break;
        case "FtoC":
            result = this.farenheitToCentigrate();
            break;
        default:
            returl = -1;
            break;
    }

    return result;
};

       
 

As you could see, more functions we add to conversion, bigger the switch case statements. It's also error prone in terms of spellings and internal handlings. Let's move on to implement MEMOIZING functionality. That'll explain how JS treats functions as a first class citizens.