2

I am using jQuery to take data from an xml file and save it to a string. The string is a switch statement which I want to become a function.

$.get('type.xml', function(xml) {
var cases=[];
$(xml).find('type').each(function(){
    index=parseInt($(this).find('earn').text());
    if($.isArray(cases[index])){
        cases[index].push($(this).find('name').text());
    }else{
        arr=$.makeArray($(this).find('name').text());
        cases[index]=arr;
    }
});
var autoearn="function(x){switch(x){";
for(i=0;i<=100;i+=5){
    if($.isArray(cases[i])){
        $.each(cases[i], function(index,v){
            autoearn+='case "'+v+'":';
        });
        autoearn+='$("input[name^=\'earn\']").val('+i+');break;';
}}
autoearn+='}}';
});

The first section makes a 2D array that associates an array of cases to their resultant output by their index. So that something that earns $10 (e.g. Meeting) will be stored in cases[10] (Meeting=cases[10][0]).

The second part writes a string that makes a puts into a switch statement that looks something like this:

function(x){    
    switch(x){
        case "Meeting":
            $("input[name^='earn']").val(10);
            break;
        case "Event1":
        case "Event2":
            $("input[name^='earn']").val(20);
            break;
    }
}

Note that the syntax for the switch cases make Event1 and Event2 have the same result.

Now autoearn is just a string that has the code for the function I want. How do make into a function? Is there a better way to do this? I'm thinking of sending it through PHP to return it back to jQuery but this whole thing seems really indirect and there is probably an easier way to do this.

Sven
  • 161
  • 1
  • 6

2 Answers2

5

First of all, make sure the code in the string is trusted, or you'll run into problems by executing arbitrary code.

You can create a function from a string as follows:

var f = new Function('arg1', 'arg2', ..., 'function code');

The above is equivalent to:

function f(arg1, arg2, ...) {
  function code
}

In your case, you would want to remove the function(x) and the opening/closing braces from the autoearn string and create the function like this:

new Function('x', autoearn)
casablanca
  • 69,683
  • 7
  • 133
  • 150
  • works great, thank you! I just forgot you could make functions like that. – Sven Nov 09 '10 at 19:36
  • The two functions are almost equivalent, The Function constructor does not have access to any of the local scope (closure), it's basically global, while the literal function can access local variables. If you do need access to local variables you can just generate the function using the evil `eval`. See http://stackoverflow.com/questions/4599857/is-eval-and-new-function-the-same-thing/4599932#4599932 – Ruan Mendes Apr 19 '11 at 23:08
1

Here's a small piece of code to take a script from a string and execute it:

  function loadScript(script) {
    var func = null;

    if (script) {
      try {
        func = new Function(script);
      } catch (eParse) {
        console.error("Error parsing script.");
        console.debug(" error : %o", eParse);
        console.debug(" script: %s", script);
      }
    }
    if (func) {
      try {
        func(); // beware of scoping here, you might want to call this differently
      } catch (eExec) {
        console.error("Error running code.");
        console.debug(" error : %o", eExec);
      }
    }
  }

BEWARE: Using new Function is basically as dangerous as using an eval statement. Be sure of what you receive for the script parameter.

haylem
  • 22,460
  • 3
  • 67
  • 96