Monday, March 30, 2015

Unceremoniously Acquiring the Global Context in Script

Untitled Document

<!--- Title: # Unceremoniously Acquiring the Global Context in Script -->

If you know you're coding in the global scope, then simply using this will suffice to ceremoniously acquire the global context! Otherwise read on to determine which enviornment you're running in and determine its global context ...

This post details a method to acquire the global context of the scripting environment when a script might be run in different environments having different named global contexts. The mechanism therefore supports script portability across a subset of environments.

An example of a script environment's global context is window for web browsers, or global for NodeJS, or self for W3C Web Workers, etc...

Scripts might choose to use the global context for a variety of reasons not excluding having a place to hang global data on, as a handle to access the root elements of the environment with, or to access elements exported into the environment by other scripts.

This blog post is supported by the discovery that trying to check for existence of an undeclared JavaScript variable via the following, arguably-intuitive, first coding attempt actually throws a scripting error.
if (undeclared_identifer) { //...
It throws error: 'Uncaught ReferenceError: undeclared_identifer is not defined'.

A quick web search revealed I should instead be using the following script to check for existence of a variable (e.g. for arbitrary_identifier) because it will not throw an error if the variable does not exist:

var exists = false; 
if (typeof arbitrary_identifier !== 'undefined') {
    exists = true;
}

Note that we're checking for existence of a variable instead of a property. When checking for a property, for example, we would instead be doing something like: obj.hasOwnProperty(propName), or, obj[propName] !== undefined, etc.

Function to Get Global Context

The following getGlobalContext() function attempts to resolve the global context variable automatically and returns it to the caller. This is done by testing for existence of well-known global context names for the environments mentioned above. Additionally this function allows the script author to override the resolution process by providing a custom function that returns a context object of choice.

This function makes thorough use of the variable existence test outlined above.

var getGlobalContext = function () {
    var gc = undefined;

    // if a custom resolver exists then use it 
    if (typeof globalContextResolver !== 'undefined' && globalContextResolver) {
        gc = globalContextResolver();
    } else {
        // otherwise try for common script environments... 
        gc = (typeof global !== 'undefined' && global) || // nodejs 
        (typeof window !== 'undefined' && window) || // browser
        (typeof self !== 'undefined' && self); // web workers, etc
    }

    // didn't resolve? 
    if (!gc) {
        throw 'Global context unresolved - you can add a custom global context resolver via variable: globalContextResolver = function() { return your_global_context;};'
    }

    return gc;
}

You will notice a globalContextResolver variable check is included inside the function - its purpose is to allow the caller to set up a custom resolution method prior to function call that will be used instead of the automatic resolution mechanism built into the function. For example, the following line defines a custom resolver that causes the getGlobalContext() function to return the window variable context.

globalContextResolver = function() { return window;}; // returns web browser window as global context 

A full Fiddle of the script is demonstrated here: Global Context Script.

Usage Scenario (sample)

This means, for example, the standard software pattern script of using a self-executing function to act as a namespace can be given a dynamically resolved global context for initialization rather than a hard-coded object.

In this example, initialization uses a hard-coded window global context for the browser environment. As such the function parameter g receives the global context window argument for use.

function(g, option) { // note: the window argument is passed into  the g parameter
  // ... 
}(window, {});

However the window variable can be replaced with a call to the getGlobalContext() function to resolve an appropriate global context like so:

function(g, option) {
  // ... 
}(getGlobalContext(), {});

You can mix and match the code to taste and scenario.

Search This Blog

Followers