2

I'm trying to dynamically create function when iterating over an array and I need the arguments in the array to be set according to the value of the current index.

For example:

var array = ['apple','orange','banana'];

I need to have these three functions:

function() { return 'apple' };
function() { return 'orange' };
function() { return 'banana' };

I tried to return a constructed function from an external one but the expression in it won't evaluate and I end up with three of these:

function() { return array[i] };

Is there a way to dynamically create such a function without using eval()?

asked Jul 1, 2013 at 8:40
1
  • 1
    what you want to do with the generated functions? Commented Jul 1, 2013 at 8:49

3 Answers 3

4

You can create the functions like so:

var funcs = {};
for (var i=0;i<array.length;i++)
{
 funcs[array[i]] = (function(val)
 {
 return function()
 {
 return val;
 };
 }(array[i]));
}

which can be called like so:

funcs.apple();// returns "apple"

But also, depending on the value of some var:

var someVar = 'banana';
if (funcs.hasOwnProperty(someVar))
{
 funcs[someVar]();
}

If what you're after is a single (possibly global) function, that depending on, for example, the URI, you just have to write this:

var myFunc = (function()
{
 var retVal = location.mathname.match(/^\/([^\/]+)/)[1];
 return function()
 {
 return retVal;
 };
}());

Note that the function won't be hoisted, as it is an expression.
I've written a lot about IIFE's (Immediatly Invoked Function Expressions), how they work and why, so best check my answer here if you don't fully understand these code snippets. It's quite easy once you get the logic, and you'll soon find yourself writing code like this all the time... tey really are incredibly powerful things, closures are!

answered Jul 1, 2013 at 8:52
Sign up to request clarification or add additional context in comments.

Comments

1

This is what I would do:

function constant(value) {
 return function () {
 return value;
 };
}
var array = ["apple", "orange", "banana"];
var fruit = array.map(constant);
alert(fruit[0]()); // apple
alert(fruit[1]()); // orange
alert(fruit[2]()); // banana

Simple. See the demo: http://jsfiddle.net/tfS2F/

You can also use the initial array as a key as follows:

alert(fruit[array.indexOf("orange")]()); // orange

See the demo: http://jsfiddle.net/tfS2F/1/

answered Jul 1, 2013 at 9:00

Comments

0

This one will not work, i leave it to illustrate the infamous loop problem:

The best way to achieve this would be to create a context var before creating the function, hope this illustrates it http://jsfiddle.net/jkymq/

var array = ['apple','orange','banana'];
var methods = {}
for (pos = 0 ; pos < array.length; pos ++){
 var target = array[pos];
 var newMethod = function(){alert (target);}
 methods[target] = newMethod;
}
for (foo in methods){
 methods[foo]();
}
answered Jul 1, 2013 at 8:44

6 Comments

target suffers from the infamous loop problem here, you need a closure!
the scope is the newMethod declaration. Would it fail?
The problem is, that variable declarations as in var target are hoisted at the top of the function. You don't get a new variable each time the loop iterates. Since you have only one variable and the functions in methods all refer to that variable, they will all evaluate to the same value ;)
yes but I have a new var target in each iteration, the jsfiddle is working properly.
@Edorka: Your fiddle works, because you're using the target variable every time. Change target to foo when looping over your methods object, and your code doesn't work anymore. your functions merely reference the global target val, so their behaviour changes whenever the value of target changes.... also try changing the method[target](); call to methods.apple(); call, it won't alert apple three times...
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.