14

I want to create a local variable dynamically. JavaScript: Dynamically Creating Variables for Loops is not exactly what I am looking for. I dont want an array. I want to access it like a local variable.

Something like:

    <script type="text/javascript">
        var properties = new Object();
        properties["var1"] = "value1";
        properties["var2"] = "value2";

        createVariables(properties);

        function createVariables(properties)
        {
            // This function should somehow create variables in the calling function. Is there a way to do that?
        }
        document.write("Outside the function : " + var1 + "<br>");
        document.write("Outside the function : " + var2 + "<br>");
    </script>

I tried the following code.

    <script type="text/javascript">
        var properties = new Object();
        properties["var1"] = "value1";
        properties["var2"] = "value2";

        createVariables(properties);

        function createVariables(properties)
        {
            for( var variable in properties)
            {
                try
                {
                    eval(variable);
                    eval(variable + " = " + properties[variable] + ";");
                }
                catch(e)
                {
                    eval("var " + variable + " = '" + properties[variable] + "';");
                }
            }
            document.write("Inside the function : " + var1 + "<br>");
            document.write("Inside the function : " + var2 + "<br>");
        }
        document.write("Outside the function : " + var1 + "<br>");
        document.write("Outside the function : " + var2 + "<br>");
    </script>

But the generated variables are not accessible outside the createVariables().

Now, I have this solution.

    <script type="text/javascript">
        var properties = new Object();
        properties["var1"] = "value1";
        properties["var2"] = "value2";

        function createVariables(properties)
        {
            var str = "";
            for( var variable in properties)
            {
                str += "try{";
                str += "eval('" + variable + "');";
                str += "eval(\"" + variable + " = properties['" + variable + "'];\");";
                str += "}";
                str += "catch(e){";
                str += "eval(\"var " + variable + " = properties['" + variable + "'];\");";
                str += "}";
            }
            return str;
        }

        eval(createVariables(properties));
        document.write("Outside the function : " + var1 + "<br>");
        document.write("Outside the function : " + var2 + "<br>");
    </script>

This works. But I am looking for an alternative/better solution. Is it possible to do it without eval?

EDIT: 04-July

Hi,

I tried a solution similar to what @Jonathan suggested.

    <script type="text/javascript">

    var startFunc = function(){
        var self = this;

        self.innerFunc = function innerFunc(){
            var properties = new Object();
            properties["var1"] = "value1";
            properties["var2"] = "value2";
            properties["var3"] = "value3";

            function createVariables(caller, props) {
                 for(i in props) { 
                     caller[i] = props[i];
                 }  
                 caller.func1();
            }
            createVariables(self, properties);
            console.log( var1 );
        }

        self.func1 = function func1(){
            console.log( "In func 1" );
            console.log( var2 );
        }

        innerFunc();
        console.log( var3 );
    }

    startFunc();


    </script>

This all works fine. But it is actually creating global variables instead of creating the variables in the function.

The "self" passed to the createVariables() function is window. I am not sure why it is happening. I am assigning the function scope to the self. I am not sure what is happening here. It is anyway creating global variables in this case.

If my question is not clear,

What I am after is creating local variables in the caller. The scenario is like

1) I am inside a function.
2) I invoke another function which returns me a map[This map contains name and value of a variable].
3) I want to dynamically create all the variables, if they are not already defined. If they are already defined [global/local], I want to update them.
4) Once these variables are created, I should be able to access them without any context.[Just the variable name]

    <script type="text/javascript">
        function mainFunc()
        {
            var varibalesToBeCreated = getVariables();
            createVariables(varibalesToBeCreated);

            alert(var1);
            alert(var2);
        }

        function createVariables(varibalesToBeCreated)
        {
            // How can I implement this function, 
            // such that the variables are created in the caller? 
            // I don't want these variables this function.
        }

        function getVariables()
        {
            var properties = new Object();
            properties["var1"] = "value1";
            properties["var2"] = "value2";  
        }


        mainFunc();
    </script>
Community
  • 1
  • 1
Paul Nibin
  • 726
  • 3
  • 10
  • 18
  • 9
    Why ? It's hard to know what real problem you're trying to solve but it's easy to guess it's the wrong solution. – Denys Séguret Jun 26 '13 at 14:10
  • any variable is local if declared within a function using var keyword. Try not to use eval, this does indeed look vastly over complex. – NimChimpsky Jun 26 '13 at 14:12
  • Just seeking a clarification of the question: are you attempting to declare variables in the outer or global scope while "inside" the function? Or are you attempting to add variables to the context of the function call (that's what the `this` keyword is for)? – Qantas 94 Heavy Jun 26 '13 at 14:14
  • 2
    I want to declare local variables where the createVariables() function is invoked. I do not want global variables. – Paul Nibin Jun 26 '13 at 14:16
  • @NimChimpsky: Of course it's complex because it's an ugly workaround. Can you do it in a more clear way? I doubt it.. On the other hand, I don't see why I would ever do this.. – Karoly Horvath Jun 26 '13 at 14:16
  • The snippets you are showing here, Paul, are not "local variables" -- you're only showing your code using the global scope. There's a difference in approach depending on the desired scope. I think we need to see a real use case instead of a vague example if you aren't getting the answers you need. – Chris Baker Jun 26 '13 at 14:31
  • @Chris: Simply wrap what code he posted within a function. – Karoly Horvath Jun 26 '13 at 14:35
  • 1
    @PaulNibin The eval solution is the only one that really works. – Jacques de Hooge Feb 17 '18 at 17:45

7 Answers7

9

Depending on the scope you'd like the variables to have, this could be accomplished in a few different ways.

Global scope

To place the variables in the global scope, you could use window[varName]:

function createVariables(variables) {
    for (var varName in variables) {
        window[varName ] = variables[varName ];
    }
}

createVariables({
    'foo':'bar'
});
console.log(foo); // output: bar

Try it: http://jsfiddle.net/nLt5r/

Be advised, the global scope is a dirty, public place. Any script may read, write, or delete variables in this scope. Because of this fact, you run the risk of breaking a different script that uses the same variable names as yours, or another script breaking yours.

Function scope (using this)

To create variables in a function's scope (this.varName), you can use bind:

var variables = {
    'foo':'bar'
};
var func = function () {
    console.log(this.foo);
};
var boundFunc = func.bind(variables);
boundFunc(); // output: bar

Try it: http://jsfiddle.net/L4LbK/

Depending on what you do with the bound function reference, this method is slightly vulnerable to outside modification of the variables. Anything that can access boundFunc can change or refer to the value of the values by using boundFunc.varName = 'new value'; This may be to your advantage, depending on use case.

Function scope (using arguments)

You can use apply to pass an array of values as arguments:

var variables = [
    'bar'
];
var func = function (foo) {
    console.log('foo=', foo);
};
func.apply(null, variables);

Try it: http://jsfiddle.net/LKNqd/

As arguments are ephemeral in nature, nothing "outside" could interfere with or refer back to the values, except by modifying the variable array and re-calling the function.

Global scope as temporary

And here's a small utility function that will make temporary use of the global scope. This function is dangerous to code that also uses the global scope -- this could blast over variables that other scripts have created, use at your own risk:

var withVariables = function(func, vars) {
   for (var v in vars){
       this[v] = vars[v];
   }
   func();
   for (var v in vars){
       delete this[v];
   }
};

// using an anonymous function
withVariables(
    function () {
        console.log('anonymous: ', foo);   
    },
    {
        'foo':'bar'   
    }
); // output: bar

// using a function reference
var myFunction =function () {
    console.log('myFunction: ', foo);   
};
withVariables(myFunction, {
    'foo':'bar'   
}); // output: bar

console.log(foo); // output: undefined

Try it: http://jsfiddle.net/X3p6k/3/

Documentation

Chris Baker
  • 49,926
  • 12
  • 96
  • 115
  • I am not able to do this....
    It tells Object [object global] has no method 'bind'
    – Paul Nibin Jun 26 '13 at 14:25
  • @PaulNibin It is not clear to me what scope you are trying to do this in. Is that literally the script you'd use? If so, you're using global scope -- don't bind, use `window[varName]` method. If that snippet is within a function, you use the binding method from the answer. – Chris Baker Jun 26 '13 at 14:29
  • 1
    That snippet is in a function. If I use "this.foo", I can access it. But actually want to create a local variable. So, I should be able to access with "foo". – Paul Nibin Jun 26 '13 at 14:32
  • `this.foo` is a scope that only exists within the function. – Chris Baker Jun 26 '13 at 14:33
  • @PaulNibin Check out the edit -- `apply` might be what you're after? – Chris Baker Jun 26 '13 at 14:37
  • P.S. you can use object or array literals `{}`/`[]` as I have done in my samples instead of the formal `new Object()` method for shorter code :) – Chris Baker Jun 26 '13 at 14:39
  • Thanks Chris, for pointing all these ways of passing arguments to function. But what I am after is creating local variables in the caller. The scenario is like 1) I am inside a function. 2) I invoke another function which returns me a map[This map contains name and value of a variable]. 3) I want to dynamically create all the variables, if they are not already defined. If they are already defined [global/local], I want to update them. 4) Once these variables are created, I should be able to access them without any context.[Just the variable name] – Paul Nibin Jul 04 '13 at 13:42
3

Here is working sample based on Chris Baker answer: Function scope (using arguments)

    function myFn() {
      function keyList(params) {
        var str = '';
        for (var key in params) {
          if (params.hasOwnProperty(key)) {
            str += ',' + key;
          }
        }
        return str.length ? str.substring(1) : str;
      }

      function valueList(params) {
        var list = [];
        for (var key in params) {
          if (params.hasOwnProperty(key)) {
            list.push(params[key]);
          }
        }
        return list;
      }
      var params = {
        'var1': 'value1',
        'var2': 'value2'
      };
      var expr = 'document.write("Inside the function : " + var1 + "<br>")'
      var fn;
      eval('var fn = function(' + keyList(params) + '){' + expr + '};');
      fn(valueList(params));
    }

    myFn();
danial
  • 4,058
  • 2
  • 32
  • 39
2

I have written short code snippet which will create both local and global variable dynamically

function createVar(name,dft){
 this[name] = (typeof dft !== 'undefined')?dft:"";
}

createVar("name1","gaurav"); // it will create global variable
createVar("id");// it will create global variable

alert(name1);
alert(id);
function outer(){
 var self = this;
  alert(self.name1 + " inside");
}
createVar.call(outer,"name1","saurav"); // it will create local variable
outer.call(outer); // to point to local variable.
outer(); // to point to global variable
alert(name1);

hope this helps Regards Gaurav Khurana

Gaurav
  • 821
  • 9
  • 11
1

The example below demonstrates how with gets a value from the object.

var obj = { a : "Hello" }
with(obj) {
  alert(a) // Hello
}

But I want to notice: with is deprecated!

Peteychuk
  • 11
  • 1
1

This answer is more or less the same as several answers above but here with a simplified sample, with and without using eval. First using eval (not recommended):

var varname = 'foo';  // pretend a user input that
var value = 42;
eval('var ' + varname + '=' + value);

And alternatively, without using eval:

var varname = prompt('Variable name:');
var value = 42;
this[varname] = value;

I hope this helps.

Source: https://www.rosettacode.org/wiki/Dynamic_variable_names#JavaScript

Darío Pm
  • 139
  • 1
  • 9
0

since you are wanting the scope of where the function is being called pass this to the function

var properties = new Object();
properties["var1"] = "value1";
properties["var2"] = "value2";
function createVariables(context) {
     for(i in properties) { 
         context[i] = properties[i];
     }   
}
createVariables(this);
console.log( var1 );
Patrick Evans
  • 41,991
  • 6
  • 74
  • 87
-1

Do you need something like this?

function createVariables(properties, context){
 for( var variable in properties){
    context[variable] = properties[variable ];
 }
}

So, calling as createVariables(properties, this) will fill the current scope with values from properties.


<script type="text/javascript">
        var properties = new Object();
        properties["var1"] = "value1";
        properties["var2"] = "value2";

        createVariables(properties, this);

        document.write("Outside the function : " + var1 + "<br>");
        document.write("Outside the function : " + var2 + "<br>");
    </script>
Jonathan Naguin
  • 14,526
  • 6
  • 46
  • 75
  • How do I pass the context? What is the context here? Is it "this" object? If I set context[variable] = properties[variable], is it creating a local variable on the caller? – Paul Nibin Jun 26 '13 at 14:18
  • @PaulNibin `context` is a reference to the object where the function will create the variables. If you pass `this` it means the local scope, but if your scope is the global you are passing the global... – Jonathan Naguin Jun 26 '13 at 14:25
  • It looks like a good solution. In the context, if a variable is already available (local/global), it will update the variable. If the variable is not available, it will create a new local variable. Is this correct? This is exactly what I want – Paul Nibin Jun 26 '13 at 14:38
  • 1
    Could you show this in action, working as you expect? http://jsfiddle.net/AqXRG/ -- does not work. Also, @PaulNibin, this method does not check to see if a variable already exists before creating it. This will plow over whatever exists with whatever is in `properties`. – Chris Baker Jun 26 '13 at 18:28
  • @Chris You are right, the case you are showing me I didn't cover it in my code (it isn't in the scope of my answer) – Jonathan Naguin Jun 27 '13 at 08:23
  • 2
    This is the opposite of making local variables. It only works because in non-strict mode `this` in the context it's being passed **IS** the global object, and you're adding properties to the global object as a result. Note that after running this function `var1` and `var2` are available everywhere, not just in that function. This jsfiddle shows that: http://jsfiddle.net/goasfgp8/ – Jimbo Jonny Mar 31 '16 at 04:19