Search code examples
javascriptreflectioneval

JavaScript: Finding a variable's value by its name, is eval acceptable here?


WARNING: As other have stated here, this problem is based upon an inflexible customer requirement. While the question is valid, you should definitely use the simpler solutions (ex: putting your settings in a single object) if possible!

I have an array of variables I want to be "watching out" for. That is: if they were previously defined in the code, I need to be able operate on their values.

var a = 'foo'; // only a gets defined

// ...more code here... IMPORTANT: I can only control what comes BELOW this line!

var target = 'exmple.com/?';
var gets = ['a', 'b', 'c']; // these are the names of the variables I want to check for

gets.forEach(function(element) { // checking each one
   if(typeof element !== 'undefined') { // if it's previously defined
  target += "&"+element+"="+eval(element); // add `&a=foo` to target
}
});

alert(target);

I'd like the alert to be printing example.com/?&a=foo

I've seen the tons of other answers not to use the eval function, and I have tried window[element] in place without success. How would it be best to do this without having to write an if/else for every variable I want to check?


Solution

  • Assuming you can't do otherwise and everything lives in the global scope, you could do without resorting to using eval(). (I'm pretty sure there must be some valid use cases for eval but I don't think this is one is one of them.)

    Since you shouldn't trust the content of these variables you shouldn't be using eval. What if your customer options get compromised? (Or simply your customer doesn't know what they're doing.)

    var css_color = 'tweet(document.cookie)';
    

    You can simply leverage the fact that the variables will be accessible from the global scope:

    const serialize_options = (...vars) =>
      vars
        .filter(v => typeof this[v] !== 'undefined')
        .map(v => `${v}=${this[v]}`)
        .join('&');
      
    console.log(serialize_options('a'));
    console.log(serialize_options('a', 'b'));
    console.log(serialize_options('a', 'b', 'c'));
    console.log(serialize_options('a', 'x', 'y'));
    <script>
    var a = '10';
    var b = '20';
    var c = '30';
    </script>