-
Notifications
You must be signed in to change notification settings - Fork 3
Namespaces and Globals
When your page needs more than a couple of common variables and functions, you need a way to divide them into packages. In JavaScript that is easy. Just create a few objects and divide your code between them.
var shapes = {};
shapes.Shape = function() {};
var tools = {};
tools.Tool = function() {};
This works well for websites with a moderate amount of code. Eventually you will want a simple way to specify a hierachialy named package supported natively by most modern languages. This classic functionality packaging can be done easily with a window resolver.
var shapes = Resolver(window)("my.shapes");
var tools = Resolver(window)("my.tools");
If you call Resolver() without a parameter, the default behaviour is the look up the package within the default namespace object. This is called the default namespace.
Undefined parts are stubbed out with plain objects. This is usually what you want to do for the package, but not for the functionality within the package.
You can assign an entry in a package using a single statement.
Resolver().set("my.shapes.IGNORE_X",5);
If you want to declare a value without overwriting a previous one set elsewhere or configured, call declare.
Resolver().declare("my.shapes.IGNORE_X",5);
If you bundle your code in one big file and use a JavaScript Scope to encapsulate it, you can keep out of the global namespace altogether by using a private namespace.
var Private = Resolver({});
will create a resolver for a private namespace using the blank object passed as a parameter. Use it to declare and resolve functionality.
Private.declare("my.shapes.Rectangle",Generator(Rectangle));
var ff = Private("my.shapes.Rectangle")(5,5);
In its basic form this approach doesn't do what you can do with local variables, but it can be used in a more advanced scenario to make a namespace and pass it among scoped scripts or even browser windows.
You could also bundle your code and use a named namespace, keeping out of the global namespace, but still allowing other scripts to resolve the contents of the namespace.
var visualns = {};
var Visual = Resolver("visual",visualns);
will create a resolver for a namespace named visual.
visualns will now point to your own alternate namespace. Calls to Visual(...) will create objects attached to visualns namespace rather than the default namespace.
Note that calling Resolver("visual",other_ns) will not change the current namespace as it is already set. To override
the existing one call Resolver("visual").override(other_ns).
Calling Resolver("visual") somewhere else will also resolve objects in the visualns namespace.
Visual.declare("my.shapes.Rectangle",Generator(Rectangle));
var ff = Visual("my.shapes.Rectangle")(5,5);
Declaration and resolution can be done exactly alike for any other namespace.
By default the global namespace is resolved. You can change this by,
var my_default = {};
Resolver("default",my_default);
This will cause all subsequent Resolver() calls to resolve within my_default.
Resolver("default").override(window);
This will cause all subsequent Resolver() calls to resolve within the global window object.
New packages in a namespace is by default created by generating a plain object. You can supply your own generator as
an option to Resolver. The default behaviour is equivalent to,
var my_resolver = Resolver("island", {}, { "generator":Generator() })
A call like my_resolver("a.b.c") will use the default generator to construct three nested objects.
function Package(enclosing,name,resolver) { this.__enclosing__ = enclosing; this.__name__ = name; }
var my_resolver = Resolver("island", {}, { "generator":Generator(Package) });
my_resolver("my.shapes.advanced");
will construct each of the packages my, shapes, and advanced as instanceds of Package, with the package name
and a reference to the enclosing package.
private_resolver.reference(full name)
returns an object with get, set, and declare.