2011-07-15 10 views
3

私は"namespace.fun1.fun2.fun3"のような文字列をクライアントから渡しました。どの機能を使用するかはサーバーに伝えています。javascriptはオブジェクトにドット文字列を変換します

この機能を安全に実行するにはどうすればよいですか?

今私がやっている:

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

にはどうすれば安全にネストの任意の深さを扱うのですか?

答えて

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

最初のパラメータは、解決するために、オブジェクト/メソッド/プロパティです。 2番目の(オプションの)パラメータは、lookup()メソッドがサイレントモードで失敗するか、一部のプロパティまたはオブジェクトが解決できなかった場合に例外をスローするかどうかを示します。デフォルトは 'throw'です。 .fun3が関数である場合、そのコール

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

を回避するために、あなたの代わりに.execute()に任意のパラメータを渡すことができます。 あなただけのプロパティ値を受信したい場合は、あなたも.get()代わりの.execute()

var val = Object.lookup('namespace.fun1.fun2.fun3').get(); 
+0

これは、これが必要とするはるかに複雑な可能性があります。 –

+0

@Squeegy:「複雑な」部分は表示されません。おそらくローカルのキャッシュですか?あなたがそのような関数をかなりたくさん使っているのなら、それはかなり良い考えです。 – jAndy

+0

素晴らしい、ありがとうございます – 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(); 

注意これは、間違ってまたは悪意のある名前空間が指定されていることを防ぎません。

+0

これは安全ではありません。クライアントがあなたをTypeErrorに陥らせないようにしています... – davin

+0

さらに、私はサーバー環境でのすべてのコストで '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

コードを変更ここではグローバルスコープから各オブジェクトに指定stratingを見つけるのですか、それが見つかった機能を実行する必要がありますループのために簡単です。

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/

そして、ここでのdoesntを参照する値が存在しないかの機能ではない場合、意味のある何かをスローしますいくつかのEROR保護です:http://jsfiddle.net/jfWra/2/

+0

レベルがない場合は失敗します。 – 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) 
} 
関連する問題