0

I am going to store some function names as strings and then use them later to make the call. I'm familiar with the pattern:

window[myStringName]();

However this does not work if the function I want to call is not directly exposed globally. I am trying to keep things namespaced and only have 1 global variable exposed for the entire script. So the question is, how do I call either of these inner functions without using eval?

var myFunc = (function(myFunc){
    myFunc.myInnerFunc = function(){
        alert('hi');
    };
    myFunc.myObj = {
        innerObjFunc: function(){
            alert('howdy');
        }
    };

    return myFunc;
}(myFunc || {}));

Or are there even any drawbacks to using eval? I was under the impression that eval is evil and should never be used or else Douglas Crockford will leave a lump of coal in my stocking.

Here is where I was going to split the string and then somehow be clever in building the call, but I am not sure how...

http://jsfiddle.net/colbycallahan/AZuUk/

carter
  • 5,074
  • 4
  • 31
  • 40
  • 2
    Why not hand around the functions themselves, as is idiomatic for JS? – deceze Jan 16 '14 at 18:00
  • 1
    This is stupid, but here's how to do it: http://jsfiddle.net/AZuUk/1/ – nderscore Jan 16 '14 at 18:01
  • Wow what an unexpected negative reaction. Here is a scenario: `
    `
    – carter Jan 16 '14 at 18:24
  • Thanks @nderscore as your code seems to work although it really doesn't make sense to me. One follow up question, why does it have to be in the head tags to work and can it possibly work outside of head tags? – carter Jan 16 '14 at 18:29
  • Because if it's not within the head tags, it's wrapped in an onload function. In that case, `myFunc` doesn't exist outside of that scope. This could be fixed by using `this` instead of `window`. Ultimately, I don't like this approach. What would make more sense would be to have some object `actions` with a property for each action that you'd like to fire. `actions = { someAction: function(){...}, anotherOne: function(){...} }` and `
    ` and call them with `actions[ actionName ]();`
    – nderscore Jan 16 '14 at 18:33
  • That is a very good point @nderscore. I really should have thought of it. :) Put your answer so I can choose it? – carter Jan 16 '14 at 18:44
  • Actually I cannot seem to make this work @nderscore for my scenario. – carter Jan 16 '14 at 21:10
  • exact duplicate of [is it evil to use eval to convert a string to a function?](http://stackoverflow.com/questions/14396647/is-it-evil-to-use-eval-to-convert-a-string-to-a-function), check my extensive list there :-) – Bergi Jan 16 '14 at 21:21
  • The pattern I showed below is better for my scenario because I wanted junior devs to be able to easily look at an HTML element and match it up to a definition. The index in the HTML element corresponds to the action defined in the configuration object they use to initiate the plugin. It covers all cases by which a function can be defined whether in the `` or in the ' – carter Jan 16 '14 at 21:34

1 Answers1

0

Here is ultimately what I decided to do. Use an array of objects similar to what @nderscore suggests. Except I store the index of the object in the data-action of my html element. Easier to show than explain I suppose.

HTML:

<div id="pretendBox"></div>

JS:

var myOptions,    
    myObj;

myObj = (function(myObj){
    myObj.myFunc = function(msg){
        alert(msg);
    };

    return myObj;
}(myObj || {}));

myOptions = [
    {        
        action: myObj.myFunc
    }
];

$.each(myOptions, function(index, value){
    $('#pretendBox').append('<div data-action="'+index+'" class="anOption">An Option</div>');
});

$(document).on('click', '.anOption', function(){
    myOptions[Number($(this).attr('data-action'), 10)].action('hi');
});

http://jsfiddle.net/colbycallahan/zTRcw/2/

carter
  • 5,074
  • 4
  • 31
  • 40