javascriptcomclosuresmsscriptcontrol

How to create dynamic object members that are able to reference enclosed variables/functions?


How would I go about creating a dynamic object in such a way that it is wrapped in a closure and then, later on, be able to add members to the object that are able to reference the enclosed variables?

As this example shows, test.myFunct() can not reference the enclosed example variable:

var example = "from global";
(function (global) {
    var example = "from closure";
    global.test = {};
}(this));

test.myFunct = fnction () { return example; };
test.myFunct(); // "from global"

So I tried creating an adder function, hoping to solve the issue, but to no avail:

var example = "from global";
(function (global) {
    var example = "from closure";
    global.test = {
        add: function (name, value) { global.mJSON[name] = value; }
    }
}(this));

test.add("myFunct", function () { return example; });
test.myFunct(); // "from global"

Is there a way to dynamically add members to an object, later in runtime, that can reference enclosed members?

Why It's Needed:

I'm working with mIRC's COM implementation to access MSScriptControl.ScriptControl's jScript engine. Due to a limitation with using mIRC, I'm limited to ~4k bytes per command execution from mIRC. As such, I need to break my JS file down into chunks of ~3500 bytes or smaller before calling the ScriptControl's AddCode, ExecuteStatement, or Eval methods.

Notes:

I'd rather not have to use static "helper" functions that return values of the variables/functions enclosed.


Solution

  • Is there a way to dynamically add members to an object, later in run time, that can reference enclosed members?

    No1, that would contradict the definition of a (javascript) closure. Just use public properties instead of enclosed variables.


    1: You could use eval to create a new function in the closure scope (from a string) and put it as a member. But that's pure evil:

    var example = "from global";
    (function (exports) {
        var example = "from closure";
        exports.addPrivileged = function(name, args, body) {
            body = arguments[arguments.length-1];
            args = Array.prototype.slice.call(arguments, 1, -1).join(", ");
            this[name] = eval("(function("+args+"){"+body+"})");
            name = args = body = null;
        };
    }(test={}));
    
    test.addPrivileged("myFunct", "return example");
    console.log(test.myFunct()); // "from closure"