About

Packages in Javascript

Packages JS provides modularity and scope management
in javascript by allowing you to create packages that explicitly state
their dependencies and the external objects they use through the
function Package, and make created functions and objects/classes
available for use by other packages through the function Export.

Similar functionality will be available in Javascript 2.0, but it will take some
time before widespread browser support will allow use to use it on a real life
project. In the meantime you can use Packages JS. It’s nothing fanciful,
but it gets the job done.

Problems with modularity in Javascript

To achieve modularity we should be able to separate code from each other. We should put code that belongs together in one file and put other unrelated code in other separate files. But just putting the code in separate files is not enough. Consider this example:

<script type="text/javascript" src="mylib.js"></script>
<script type="text/javascript" src="mysite.js"></script>

mylib.js:
function myFunction() {
  return "cool!";
}

mysite.js:
alert("My site is " + myFunction());
// alerts: "My site is cool!"

Now imagine some other library was added to the page:

<script type="text/javascript" src="mylib.js"></script>
<script type="text/javascript" src="otherlib.js"></script>
<script type="text/javascript" src="mysite.js"></script>

otherlib.js:
function myFunction() {
  return "broken!";
}

Can you guess what the alert will say? The problem is that your code in mysite.js and mylib.js is not protected from change by other code, because all code shares the same global namespace. Your ‘myFunction’ was simply overwritten by the one in otherlib.js so now your site is alerting it’s visitors that it’s broken. The problem is called naming collisions or namespace pollution.

Traditional solutions

A solution that’s often used to circumvent this problem is wrapping code in an anonymous function which is immediately executed, like this:

(function(){
  // Code in here is in a local scope
  function myFunction() {
    return("cool!");
  }
  // we can use myFunction here...
  alert("My site is " + myFunction());
  })();
// ...but not here

Because local variables will override global ones with the same name, our call to myFunction will always call the correct function. Guaranteed. But the problem here is that we can’t break up the code into separate files because it has all got to be placed inside that anonymous function.

A second way of solving the problem is by simulating namespaces ourselves so we pollute the global scope as least as possible. Here is how that works:

mylib.js:
var mylib = {
  // Code in here is in the mylib object scope
  myFunction: function() {
    return "cool!";
  }
};

mysite.js:
alert("My site is " + mylib.myFunction());

Packages JS solution

Packages JS combines both traditional solutions. Your code is in a callback function passed as the third argument to Package() and you Export() the objects you wan to expose to other modules. Those exported objects get placed in an artificial namespace and get injected by Packages JS into the callback function of other packages if they define an argument with the same name as the exported object. Here is how the code would look with Packages JS.

mylib.js:
Package("mylib", [], function(){
  function myFunction() {
    return "cool!";
  }
  Export(myFunction, "myFunction");
});

mysite.js:
Package("mysite", ["mylib"], function(myFunction) {
  alert("My site is " + myFunction());
  // alternatively, access the object through it's namespace
  alert("Packages JS is " + mylib.myFunction());
});

Check it out on the live demo page.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s