daemonl

In case you were wondering...

JS109 - Organising Code

There are a few principals to organising code in JavaScript. I will attempt to give reasons for them, but an extra really good reason for all of them is that 'everyone's doing it' - which in the case of code shouldn't be viewed as peer pressure. It means that it will be easy to find resources which look similar to your code, and when you post your code on Stack Overflow, people will understand what you are going for.

Modules

There is no language construct in JavaScript called 'module' - It's simply a pattern we use to organise code. The principle is: Split your program into small sections of related functionality, then implement them in ways which don't effect any other part of the program.

JavaScript's variables are 'lexically scoped' - a refresher: A variable is accessable from anywhere inside the function(){} it is written inside of, and any function inside that, so long as a some other more 'local' function doesn't define the same variable name (with var or in the parameters list of the function).

So the way to do it: Wrap your module in a function. Easy. There's a few ways to do that:

var moduleMaker = function(){

   // Local Things
   var localVariable = 0;
   var localFunction = function(param) { ... };

   // Specify the 'externally accessible' parts
   return {
      f1: localFunction
      f2: localFunction2
   }
}

var module = moduleMaker();

// Then you can use
module.f1 (100);
module.f2 (100);

It's pretty good - you are only changing two 'global' variables ('moduleMaker' and 'module' in this case), and if you are careful with naming, that should be the only names which use window.module* - so it won't effect any other code, but still can do whatever it needs to do.

We can go one better, and only place one variable in the global scope. You don't really need to have 'moduleMaker.

One thing first, to make the other way easy to read, you need to know this:

var a = "Str";
a.big();

can be shortened as:

("Str").big();

But doesn't use any variables. so:

var f = function(){ ... };
f();

Is the same as:

(function() { ... }());

and is called an 'anonymous function' because it doesn't have a name. It is called as soon as it is defined. (by the '()')

Now we are ready, the second way:

var module = (function(){
  var localVariable = 0;
  var localFunction = function(){ ... }

  var export = {}
  export.f1 = localFunction;

  return export;
})();
module.f1();

Or, another way to achieve the same thing:

(function(){
  var localVariable = 0;
  var localFunction = function(){ ... }

  var export = {}
  export.f1 = localFunction;

  window.module = export;
}());
module.f1();

So that function is called as soon as it loads ( the () calls the function ) and defines a new global object (window.module) as a copy of the local object (export, but it could be whatever you want to call it).

The end result is the same, but you could define multiple 'window.' objects if that were appropriate. - Remember, of course, that we are trying to reduce the number of 'window.' variables.

Those are the two main ways of 'exposing' a variable (or function) from your module - there are some more which work with specific libraries, but they are based on those two.

The variable we expose doesn't have to be a simple list of functions, it could be a constructor:

(function(){
    var Constructor = function() {
        this.f1 = function(){ ... };
    }
    Constructor.prototype.toString = function(){
        return // A string representation
    }
    window.NameOfTheClass = Constructor;
})();

var obj = new NameOfTheClass;

Or anything else you want to expose.

None of these examples used anything else other than built in JavaScript functions. If you have a module which uses things from another module, you can pass it in as a variable to the module's defining function.

var Module1 = (function(){
    return {
        f1: function(){ /* Something */ },
        f2: function(){ /* Something */ }
    }
})();

var Module2 = (function (Module1) {
    // do something with Module 1
    return {
        f1: function(){ /* Something */ },
        f2: function(){ /* Something */ }
    }
})(Module1);

In large applications, it's normal to develop with one module per file. Then you have to include all of the script files in your HTML page - or you could use a library like require.js to do that for you.