3

I have a string like this "namespace.fun1.fun2.fun3" passed from the client. It's telling the server which function to use.

How do I safely run the function?

right now i'm doing:

var runthis = string.split('.')
namespace[runthis[1]][runthis[2]][runthis[3]]

How do I handle arbitrary depth of nesting safely?

6 Answers 6

5

A little function I wrote. I use it in most of my applications:

Object.lookup = (function _lookup() {
    var cache = { };

    return function _lookupClosure( lookup, failGracefully ) {
        var check   = null,
            chain   = [ ],
            lastkey = '';

        if( typeof lookup === 'string' ) {
            if( cache[ lookup ] ) {
                chain = cache[ lookup ].chain;
                check = cache[ lookup ].check;
            }
            else {
                lookup.split( /\./ ).forEach(function _forEach( key, index, arr ) {
                    if( check ) {
                        if( typeof check === 'object' ) {
                            if( key in check ) {
                                chain.push( check = check[ key ] );
                                lastkey = key;
                            }
                            else {
                                if( !failGracefully ) {
                                    throw new TypeError( 'cannot resolve "' + key + '" in ' + lastkey );    
                                }
                            }
                        }
                        else {
                            if( !failGracefully ) {
                                throw new TypeError( '"' + check + '" ' + ' does not seem to be an object' );   
                            }
                        }
                    }
                    else {
                        lastkey = key;
                        chain.push( check = window[ key ] );
                    }
                });

                if( check ) {
                    cache[ lookup ] = {
                        chain: chain,
                        check: check
                    };
                }
            }
        }

        return {
            execute: function _execute() {
                return typeof check === 'function' ? check.apply( chain[chain.length - 2], arguments ) : null;
            },
            get: function _get() {
                return check;
            }
        };
    }
}());

usage:

Object.lookup( 'namespace.fun1.fun2.fun3' ).execute();

The first parameter is the object/method/property to resolve. The second (optional) parameter indicates whether or not the lookup() method shall fail silently or throw an exception if some property or object could not get resolved. default is 'throw'. To avoid that call

Object.lookup( 'namespace.fun1.fun2.fun3', true ).execute( 'with', 'paras' );

If .fun3 is a function, you can pass in any parameters into .execute() instead. if you just want to receive the property value, you can also call .get() instead of .execute()

var val = Object.lookup( 'namespace.fun1.fun2.fun3' ).get();
Sign up to request clarification or add additional context in comments.

5 Comments

That's likely far more complex that this needs here.
@Squeegy: I don't see the 'complex' part.Probably the local caching ? which is a pretty good idea if you're using such a function quite a lot.
@Harry: well I've updated the method. Should work better now.
@Harry: Oh true, you need just to replace it by global
Why check === 'object'? Should be fine if it's also a function right.
2

(I may be misinterpreting the question, but this is what came to mind)

var s = "space.f.g.h.i.j.k.l.m",
  a = s.split( "." ),
  fn = eval( a[0] );

for ( var i = 1; i < a.length; i++ ) {
  fn = fn[ a[i] ];
}

fn();

Note: this won't guard against the namespace being specified incorrectly or maliciously.

2 Comments

That's unsafe. You're allowing a client to run you into a TypeError without even making it hard...
furthermore, I would avoid eval() at all costs in a server-environment. Especially if the data comes from somewhere else (like in this case). Asking for terrible trouble.
1

This should do:

var get = function(obj, key) {
  var s = key.split('.')
    , i = 1
    , l = s.length;

  for (; i < l; i++) {
    obj = obj[s[i]];
    if (!obj) return;
  }

  return obj;
};

get({hello:{world:{}}}, 'ns.hello.world');

edit: changed code a bit

Comments

1

Here's a simple for loop that should do find each object specified strating from the global scope, and then run the function it finds.

window.namespace = { fun1: { fun2: { fun3: function() { alert('hi!') }}}};

runFunc = function(address) {
    var addressArray = address.split('.'),
        current = window,
        i = 0;

    for (i = 0; i < addressArray.length; i++) {
        current = current[addressArray[i]];
    }

    current();
};

runFunc('namespace.fun1.fun2.fun3');

http://jsfiddle.net/jfWra/1/

And here's some eror protection that will throw something meaningful if the value referenced doesnt exist or is not a function: http://jsfiddle.net/jfWra/2/

1 Comment

this will fail if any level is missing.
0

Here's another simple solution using a recursive function:

function run(str, context) {
  var path = str.split(".")
  if path.length == 1 {
     context[path[0]].call()
     return;
  }

  if(typeof context == 'undefined') {
     context = window[path[0]]
  } else {
     context = context[path[0]]
  }
  run(path.splice(1).join('.'), context)
}

Comments

0

Two years later there is this module: https://github.com/daaku/nodejs-dotaccess.

var get = require("dotaccess").get;
var o = {a:{b:{c:'deep'}}};
console.log(get(o, 'a.b.c'));

Comments

Your Answer

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.