JavaScript将点表示法字符串转换为对象

3

我是一名有用的助手,可以为您进行文本翻译。

我有一个来自客户端的字符串,格式如下"namespace.fun1.fun2.fun3"。它告诉服务器要使用哪个函数。

我该如何安全地运行这个函数?

目前,我正在执行以下操作:

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

如何安全地处理任意深度的嵌套?

6个回答

5
我写了一个小函数,我在大部分应用程序中都使用它:
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;
            }
        };
    }
}());

用法:

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

第一个参数是要解析的对象/方法/属性。第二个(可选)参数指示lookup()方法是否应该在某些属性或对象无法解析时静默失败还是抛出异常。默认值为'throw'。如果要避免这种情况,请调用
Object.lookup( 'namespace.fun1.fun2.fun3', true ).execute( 'with', 'paras' );

如果.fun3是一个函数,你可以在.execute()中传入任何参数。 如果你只想获取属性值,也可以调用.get()而不是.execute()
var val = Object.lookup( 'namespace.fun1.fun2.fun3' ).get();

这可能比这里需要的要复杂得多。 - Alex Wayne
@Squeegy:我没有看到“复杂”的部分。可能是本地缓存?如果你经常使用这样的函数,那么这是一个非常好的想法。 - jAndy
@Harry:好的,我已经更新了这个方法。现在应该会更好用了。 - jAndy
@Harry:没错,你只需要用 global 替换它即可。 - jAndy
为什么要检查 === 'object'?如果它也是一个函数,那应该没问题吧。 - Harry

2
(我可能误解了问题,但这是我想到的)
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();

注意:这并不能防止命名空间被错误或恶意地指定。

那是不安全的。你甚至都没有让它变得困难,就允许客户端将你带入 TypeError 的境地…… - davin
此外,在服务器环境中,我会尽量避免使用eval()。特别是如果数据来自其他地方(就像在这种情况下)。这样做会带来可怕的麻烦。 - jAndy

1

这应该可以:

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');

编辑:稍作修改代码


1
这是一个简单的for循环,应该从全局范围内查找每个指定对象,然后运行它找到的函数。
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/

这里有一些错误保护,如果引用的值不存在或不是函数,则会抛出一些有意义的内容:http://jsfiddle.net/jfWra/2/


如果任何级别缺失,此操作将失败。 - jAndy

0

这里是另一个使用递归函数的简单解决方案:

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)
}

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接