Javascript sandbox pattern

Introduction

Kenneth Truyers

Javascript sandbox pattern

Javascript sandbox pattern

A few years ago I wrote a post about Javascript namespaces and modules. In that post I discussed a pattern for isolating your code from outside code. I also promised to write up another pattern, the javascript sandbox pattern. I never did though. Lately I received a few emails about this and decided to write it up eventually. While 3 years have past since then, and a lot has happened in the Javascript world, I still think this is a valuable pattern, if only for historical purposes. If you’re using ES6, there are probably better alternatives, but it still is a good way to understand the semantics of Javascript.

The namespace pattern described in my other post has a few drawbacks:

It relies on a single global variable to be the application’s global. That means there’s no way to use two versions of the same application or library. Since they both need the same global name, they would overwrite each other.

The syntax can become a bit heavy if you have deeply nested namespaces (eg: myapplication.services.data.dataservice)

In this post I want to show a different pattern: a javascript sandbox. This pattern provides an environment for modules to interact without affecting any outside code.

Sandbox constructor

In the namespace pattern, there was one global object. In the javascript sandbox this single global is a constructor. The idea is that you create objects using this constructor to which you pass the code that lives in the isolated sandbox:

new Sandbox(function(box){
// your code here
});

The object box, which is supplied to the function will have all the external functionality you need.

Adding Modules

In the above snippet, we saw that the sandboxed code receives an object box. This object will provide the dependencies we need. Let’s see how this works. The Sandbox constructor is also an object, so we can add static properties to it. In the sample below we’re adding a static object modules. This object contains key-value pairs where the key indicates the module name and the value is a function which returns the module.

First we iterate over all the modules and push the names of all of them into an array. Next, we get each module from the static modules object and assign it to the current instance of the box. Lastly we pass the instance to the sandboxed code. That ensures the box has access to those modules.

Improvements

While the above is a good proof of concept, it requires some modifications to make it more versatile and safer to use.

Enforce constructor usage

First of all, let’s make sure that it’s always called as a constructor and not just with a regular function-call:

Allow module specification

Next, we want to be able to define which modules we are going to use so that only those modules will be initialized and passed. We do this by accepting an array of module names and then only adding those modules to the box, instead of iterating over all the modules. That makes our constructor a bit simpler:

Optional arguments

We want to make the modules argument optional. If it’s not provided, we will use all the modules. We also want to add the ability to pass in the modules one by one as strings, instead of in an array. For that we need to do a bit of argument parsing and again iterate over all the modules:

Arguments destructuring

Currently, the client-code has to access the modules through the box-instance. It would be nicer if we could pass in the modules as separate arguments. This makes the dependencies even more explicit. To do so, instead of calling the callback directly, we can use apply to execute the callback. Also, instead of initializing the modules as properties on the sandbox, we save them in an array:

Conclusion

The Javascript sandbox let’s you isolate code from outside factors. It also allows you to explicitly define dependencies which reduces coupling and makes it easier to test. While there are other patterns to do this, and certain framework have this built in, this could be a good pattern to use if you’re still working with ES5 and no frameworks.