Thursday, January 21, 2016

Scoping functions in JavaScript (but not TypeScript)

Being able to break down a problem down into smaller parts is good. If you take a big function and break it into a bunch of small functions you have most likely made your code more readable. Metric wise, you will have decreased your cyclomatic complexity, but there is a price. When you do this you suddenly have many entry points into your functionality instead of one. You have a whole bunch of functions that only exist for another function, but are exposed at the same level as your original function. The basic thing to do is makr them 'private'. This is telling the next person that these are only called from inside the function and they can more easily track down where they are called from. But you are still losing/concealing structural information. You have to dig around to understand the scope of where a function is used. What would be nicer would be to have functions that are only defined within the contect of another function. We can do this in JavaScript:

var bigThing = () => {
    var smallThingOne = () => { ... }
    var smallThingTwo = () => { ... }

    smallThingOne();
    smallThingTwo();
}

SmallThingOne and SmallThingTwo only exist in the context of BigThing. But this solution is bad. The reason is because every time you call BigThing it will redefine SmallThingOne and SmallThingTwo. This will be a lot of wasted effort. This can easily be fixed by shifting the pattern to:


var bigThing = (() => {
    var smallThingOne = () => { ... }
    var smallThingTwo = () => { ... }

    return () => {
        smallThingOne();
        smallThingTwo();
    }
})();

This uses an IIFE (Immediately Invoked Function Execution) to create a closure that all copies of BigThing have access to, but these functions are only created when you first define BigThing. These function are also nicely isolated inside the closure and can not be accessed by the outside world.  You can even nest this pattern like so:

var bigThing = (() => {
    var smallThingOne = (() => {
        var weeThing = () => { ... };
        return () => {
            weeThing();
        }
    })();
    var smallThingTwo = () => { ... }

    return () => {
        smallThingOne();
        smallThingTwo();
    }
})();

This is a very nice pattern to make the clear the structure and scope of your functions in JavaScript. This, however, does not work with the TypeScript class pattern. TypeScript wants to force you into certain patterns that are like Java or C# without providing the power of Java or C#. In a Java/C# context you could do some similar scoping with private inner classes, but you don't have that capability in TypeScript.

No comments:

Post a Comment