3

Yeah, there are numerous questions like How to turn a String into a javascript function call? or How to execute a JavaScript function when I have its name as a string.

But what if we have not a plain function name, but an object property name which in fact is a function?

Like:

var callMe = 'foo.bar.baz';

and the code expected to be called is:

window.foo = {
    bar: {
        baz: function() {
            alert('Eureka!');
        }
    }
};

Why I need this: the callback parameter is passed via url and it can (by application design) be either a function name or FQN of object's property.

Any ideas others than eval()?

UPD:

My final implementation:

var parts = callbackName.split('.'),
    callback;

for (i in parts) {
    if (!callback) {
        callback = window[parts[i]];
    } else {
        callback = callback[parts[i]];
    }

    if (typeof callback === 'undefined') break;
}

if (typeof callback === 'function') {
    callback();
} else {
    console.error('Passed callback is not a valid function');
}
Community
  • 1
  • 1
zerkms
  • 249,484
  • 69
  • 436
  • 539

4 Answers4

5

try

window['foo']['bar']['baz']()

If this works for you, should be easy to translate 'foo.bar.baz' into that.

Itay Moav -Malimovka
  • 52,579
  • 61
  • 190
  • 278
  • Yep it does... It was so obvious :-S – zerkms Feb 02 '12 at 03:17
  • 2
    You can always relate to a Sherlock Holmes story, where the Scotland Yard where looking in a house for a letter and couldn't find it. They brought Holmes, who walked to the desk in the study and picked an envelop that was lying on top of it. that was the letter... – Itay Moav -Malimovka Feb 02 '12 at 03:20
1

See the code below and check out the fiddle ( http://jsfiddle.net/bxsHp/ ) :

window.foo = {
    bar: {
        baz: function() {
            alert('Eureka!');
        }
    }
};
//foo.bar.baz();
var callme = "foo.bar.baz";
var fn = window[callme.split(".")[0]];//get the first prop. bar
var len = callme.split(".").length;//length of obj tree
for(i=1;i < len;i++)
{//search for the next obj  
  fn = fn[callme.split(".")[i]];
}
if(typeof(fn) == "function")
{//check and call
  fn();
}
gideon
  • 19,329
  • 11
  • 72
  • 113
1

You could always make use of reduce().

callMe.split('.').reduce(function(prev, value) {
    return prev[value] || function() {};
}, window)();

jsFiddle.

The || function() {} is to prevent an error if the object/function list is undefined somewhere. If you are using jQuery, you could swap the empty function literal with $.noop().

Of course, supporting older IEs will mean you need to shim Array.prototype.reduce().

alex
  • 479,566
  • 201
  • 878
  • 984
0

This is probably not the most elegant way of doing this, but it should work:

var callMe = "foo.bar.baz".split('.');

var callMeParts = callMe.split('.');

var fnCallMe = null;
var obj = window;
for (var i = 0; i < callMeParts.length; i++) {
    var prop = callMeParts[i];
    if (typeof obj[prop] === 'undefined') break;

    if ((i + 1) === callMeParts.length && typeof obj[prop] === 'function') {
        fnCallMe = obj[prop];
        break;
    }
    obj = obj[prop];
}

if (fnCallMe !== null) {
    fnCallMe.call(obj); // Call the function using the function container as the "scope"
}
Jordan S. Jones
  • 13,703
  • 5
  • 44
  • 49