Search code examples
javascriptbindingcode-generationdynamic-method

Javascript: How to build a method dynamically from string data?


I have an XML document that defines a task, which is a list of actions to be performed on certain data. I need to convert this "task list" to a Javascript method which can be called at some later time, which in turn calls a series of pre-defined methods, with the appropriate data. How would you achieve this?

Important Clarification:
I'm not worried about the XML parsing. I'm more interested in how to actually build the Task Method, including binding the essential data to the pre-defined action methods. That's the part I'm struggling with.

Edit: I've revised my example to make it a bit more interesting, and hopefully a bit clearer.

XML:

<task id="enter-castle">
    <if holding="castle-key">
        <print message="You unlock the castle door and enter." />
        <destroy item="castle-key" />
        <goto location="castle" />

        <else>
            <print message="The castle door is locked." />
        </else>
    </if>
</task>

Javascript:

Game = {

    print: function(message) {
        // display message
    },

    destroy: function(item) {
        // destroy the object
    },

    goto: function(location) {
        // change player location
    },

    ifHolding: function(item) {
        // return true if player has item
    }
};

parseTask(taskNode) {

    var taskId = taskNode.getAttribute('id');

    // What goes here??

    Game.tasks[taskId] = /* ??? */;
}

When I call parseTask() on the <task id="enter-castle"> node, this should create a function that, in effect, does the following when called:

Game.tasks.enterCastle = function() {
    if (Game.ifHolding('castle-key')) {
        Game.print("You unlock the castle door and enter.");
        Game.destroy('castle-key');
        Game.goto('castle');
    } else {
        Game.print("The castle door is locked.");
    }
}

Solution

  • What you want are closures.

    function createMethod(arguments) {
        var task = doSomethingWithYour(arguments);
        return function(xmlData) { // <- this is the fundamental part
            // do the task with your data
            // the "task" vars are still available
            // even if the returned function is executed in a different context
        }
    }
    

    This allows you to create an own method for each task. Don't use the Function constructor or eval.