2011-03-09 53 views
4

我希望能夠通過名稱將引用傳遞給另一個JavaScript函數。如果它只是一個全局函數,是沒有問題的:根據名稱調用對象成員的JavaScript函數

function runFunction(funcName) { 
    window[funcName](); 
} 

但是,假設該函數可以是任意對象的成員,例如:

object.property.somefunction = function() { 
// 
} 

runFunction("object.property.somefunction")不起作用。我知道我能做到這一點:

window["object"]["property"]["somefunction"]()

因此,儘管可以編寫代碼來解析字符串並找出層次結構這種方式,這似乎是工作:)所以我想知道,如果有什麼更好的方式去使用eval()當你有

​​
+0

你爲什麼需要這個?直接調用函數有什麼問題?似乎不必要的複雜。 – Cfreak 2011-03-09 15:19:00

+0

@Cfreak:這取決於他的弦是從哪裏來的。 – SLaks 2011-03-09 15:19:42

+0

函數名稱來自服務器。 – 2011-03-09 15:23:17

回答

2

都能跟得上 - 除了使用eval我不知道在JavaScript中,而不是建立正走對象樹的另一種方式沃克 - 幸運的是,這是很容易做到:

/** 
* Walks down an object tree following a provided path. 
* Throws an error if the path is invalid. 
* 
* @argument obj {Object} The object to walk. 
* @argument path {String} The path to walk down the provided object. 
* @argument return_container {Boolean} Should walk return the last node *before* the tip 
* (i.e my_object.my_node.my_other_node.my_last_node.my_attribute) 
* If `true` `my_last_node` will be returned, rather than the value for `my_attribute`. 
* @returns {Mixed} Object or the value of the last attribute in the path. 
*/ 
function walk_path(obj, path, return_container) { 
    return_container = return_container || false; 
    path = path_to_array(path, "."); 
    var ln = path.length - 1, i = 0; 
    while (i < ln) { 
     if (typeof obj[path[i]] === 'undefined') { 
      var err = new ReferenceError("The path " + path.join(".") + " failed at " + path[i] + "."); 
      err.valid_path = path.slice(0,i); 
      err.invalid_path = path.slice(i, ln+1); 
      err.breaking_point = path[i]; 
      throw err; 
     } else { 
      var container = obj; 
      obj = obj[path[i]]; 
      i++; 
     } 
    } 
    // If we get down to the leaf node without errors let's return what was asked for. 
    return return_container ? container : obj[path[i]]; 
}; 

/** 
* path_to_array 
* 
* @argument path {string} A path in one of the following formats: 
* `path/to/file` 
* `path\\to\\file` 
* `path.to.file` 
* `path to file` 
* @argument sep {string} optional A seperator for the path. (i.e. "/", ".", "---", etc.) 
* 
* If `sep` is not specified the function will use the first seperator it comes across as the path seperator. 
* The precedence is "/" then "\\" then "." and defaults to " " 
* 
* returns {Array} An array of each of the elements in the string ["path", "to", "file"] 
*/ 
function path_to_array(path, sep) { 
    path = is_string(path) ? path : path + ""; 
    sep = is_string(sep) ? sep : 
       path.indexOf("/") >= 0 ? "/" : 
       path.indexOf("\\") >= 0 ? "\\" : 
       path.indexOf(".") >= 0 ? "." : " "; 
    /* Alternately use SLak's 
    sep = is_string(sep) ? sep : /[ \\/.]/; 
    if you want simpler code that will split on *any* of the 
    delimiters by default. */ 
    return path.split(sep); 
} 

function is_string(s) { return typeof s === "string"; } 

然後,只需調用它像這樣:

walk_path(my_object, "path.to.my.function")(); 
+0

的行[是的,我已經有了代碼可用...是的,這是企業*版本的@SLaks代碼。 ;-) – 2011-03-09 15:20:47

+0

爲什麼不在'/[/\/.]/'上分割? – SLaks 2011-03-09 15:22:22

+2

比重新發明輪子好多了!完善。 – 2011-03-09 15:28:44

7

其他你可以打電話funcName.split('.')和遍歷結果數組,像這樣一個選擇。

在你的情況,你可以拆分基於'.'帕拉姆然後構造你的

window["object"]["property"]["somefunction"]() 
0

儘量避免:這,不是使用eval()

+0

你剛纔重申了他的問題。 – SLaks 2011-03-09 15:18:36

+0

@SLaks - 我認爲是,OP需要避開eval()。除此之外,我建議他根據'。'分割,但您已經給出了完整的答案;)。我更喜歡'window [array [0]] [array [1]] [array [2]]()' – 2011-03-09 15:20:55

相關問題