In the previous post we have seen how to create JavaScript objects literals, we also saw how we can use those to encapsulate parts of our code, creating de facto  reusable modules.

But if you come from Java, or .Net development you probably missed one thing: we haven’t seen yet how we can define public, and private properties. Indeed, in this example all our properties, and methods are public, and accessible from outside:

var person = {
    name: "John",
    age:35,
    greet: function ()
    {
          console.log("Hello!");
    }
}

Now, if we are are writing a library to add some functionality that we may want to reuse in different projects usually we don´t want to have all our functions open to be accessible, and therefore modifiable. What we want is to keep an API open to the public, with internal functions, and/or variables hidden.

We can use the module pattern to emulate the concept of public/private variables that we found in class-oriented languages like Java. But before we get into the details of how the module pattern works, there are a couple of JavaScript concepts that we should revise:

  • JavaScript scope
  • Self Invoking functions

JavaScript Scope

The JavaScript scope determines the visibility of variables; in JavaScript we have two types of scope:

  • Global Scope: variables defined in the global scope are accessible from anywhere in the application
  • Local Scope: every time we define a function we create a local scope: all variables defined inside the function are visible only inside that function.

Lets see an example of how this works:

//Global variable
var cat = "Tom";

//print 'I am Tom'
console.log("I am "+ cat);

function trap()
{
  //Local scoped variable
  var mouse = "Jerry"
  console.log(cat + " caught " + mouse + "!!");
}

trap();

Which produces the expected result of printing to the JavaScript console Tom caught Jerry!!.

Notice that the variable cat is visible inside trap function, but if we try to access the variable mouse from outside the trap function we will get an error:

var cat = "Tom";
function trap()
{
//Local scoped variable
var mouse = "Jerry"
console.log(cat + " caught " + mouse + "!!");
}
console.log("Mouse:" + mouse);

Output of the code above: ReferenceError: mouse is not defined

Something that puzzles developers who come to JavaScript from other languages is that the following code will actually print the message Mouse:Tom to the console … without errors:

var cat = "Tom";
function trap()
{
mouse = "Jerry"
console.log(cat + " caught " + mouse + "!!");
}
trap();
console.log("Mouse:" + mouse);

This is due to these 2 factors:

    • We didn’t use the word var to declare the variable mouse: we created an undeclared variable, and undeclared variable are always global.
    • We run the method trap()(undeclared variable does not exist till the code assigning them is executed)

Self Invoking functions

A Self invoking function is a function  that runs automatically when it is created.

//Normal function
//Function is declared, but not executed.
function sayHello()
{
  console.log("Hello");
}

//Self executing function
// prints "Hello" to console
(function sayHelloNow()
{
  console.log("Hello");
}());

In order to run a function we need to add () after the name of the function. To create self-executing functions we can use the nomenclature used above:

(function myfunction() {
//code here
}());

or this equivalent one:

(function myfunction() {
//code here
})();

Self invoking functions can also be named – as in the example above – or anonymous. An anonymous function is one that it is not bound to a identifier:

(function() {
//code here
})();

Module pattern

Using what we have learned so far about the JavaScript scope, and self executable functions, we can implement the Person object using the Module pattern:

var Person = (function () {

  var  name= "John";
  var age = 35;

  return {

    greet: function () {
      console.log("Hello!");
    },
    getName: function ()
    {
      return name;
    },
    getAge: function() {
      return age;
  	}
  };

})();
Person.greet();
console.log(Person.getName());
console.log(Person.Name);
//returns undefined

Notice that name, and age are defined as local variables in an anonymous self-invoking function, meaning they are not accessible outside the function in which they are declared. For that reason calling directly to Person.Name returns undefined.

In order to access those variables we have to use the methods we have exposed in our return scope. This allows us to simulate the public/private concept.

Advertisements