从名称中获取JavaScript函数对象作为字符串?

时间:2009-04-21 15:30:52

标签: javascript

在JavaScript中,如果我在变量中有一个字符串,有没有办法获得对具有该匹配名称的函数对象的引用?请注意,我可以使用jQuery,因此我也可以使用它的任何辅助方法。

例如:

myFunction = function(){};

var func_name = "myFunction";
var myFunctionPtr = ???  //how to get the function from the name

由于

9 个答案:

答案 0 :(得分:67)

如果您知道它可以使用它的全局功能:

var functPtr = window[func_name];
//functPtr()

否则将 window 替换为包含该函数的父对象。

答案 1 :(得分:20)

我刚刚在Firebug中做了一个快速测试,我只能通过eval()名称来获取名称中的函数...我觉得使用eval()很脏,但它似乎得到了这里完成的工作相当不错。

var myFunctionPtr = eval(func_name);

答案 2 :(得分:15)

这绝不是首选方法。您可以在func_name之类的内容中保留对函数的引用,而不是将函数名称保留在func_to_call中。

如果您绝对需要将函数引用保留为字符串,则通常会使用哈希表将任意名称映射到变量(JS具有使其成为可能的第一类函数)

myFunction = function(){};   
var obj = {func_name: myFunction};

obj['func_name']();//executes the function

Fiddled(我不知道为什么,这是一个如此小的剧本:)。

有人建议您使用eval(func_name) - 但是由于JS范围限制,这很快就会失控。

您还将myFunction = function(){};声明为全局变量。一方面,它允许您将其引用为window[func_name],但另一方面它会污染全局范围。

答案 3 :(得分:9)

这个[func_name]应该给你这个功能。

var myfunc = this[func_name];
myfunc();

答案 4 :(得分:5)

这取决于在哪里 该函数是(或不是)声明的。

如果它是全局并且未通过let name = ...const name = ...语法声明(并且它不是使用class声明的类构造函数),则可以通过寻找它作为全球对象的属性。 (这些警告都是ES2015的内容;更多内容。)您可以在全局范围内以松散模式通过this获取对全局对象的引用;浏览器还会为您提供一个名为window的全局。所以假设一个浏览器:

if (typeof window[func_name] === "function") {
    // ....
}

如果可能是全局的,而只是在范围内,因为你的代码关闭它,或者它是使用我提到的那些ES2015机制之一创建的,那真的没有好办法检查eval以外的其他人:

if (eval("typeof " + func_name) === "function") {
    // ....
}

使用eval是最后的选择,您必须 使用严格控制的输入。但是当你必须,并且你有严格控制的输入时,它就没问题了。

关于ES2015警告:

letconstclass是非常有趣的野兽:在全球范围内使用时,它们会创建全局变量,但它们不会在全局对象上创建属性。从ES2015开始,虽然全局对象的所有属性都是全局对象,但并非所有全局对象都是全局对象的属性。这是试图控制受到严重污染的全局命名空间并为JavaScript绑定模型带来更高安全性的所有部分。 (现在我们有了真正的模块。)

所以(请注意,这只会在最先进的浏览器中运行):

// Global scope, in a browser (because I used `window` and `document.body`) that
// implements this aspect of ES2015 (as I write this, Firefox's SpiderMonkey
// doesn't, Chrome's V8 does on the latest Chrome; expect SpiderMonkey and IE
// to catch up pretty quick (didn't test IE Edge, maybe it's already there)

// Strict mode isn't required for this behavior, but for the moment V8 only
// supports the block-scoped constructs in strict mode.
"use strict";
let tbody = setup();

// Old-fashioned var: Creates a property on the global object, so
// we get "function, function"
var f1 = function() { /*...*/ };
result("var declaration", typeof f1, typeof window["f1"]);

// Function declaration: Creates a property on the global object, so
// "function, function"
function f2() {}
result("function declaration", typeof f2, typeof window["f2"]);

// `let` declaration: Doesn't create property on global object, so
// "function, undefined"
let f3 = function() { /*...*/ };
result("let declaration", typeof f3, typeof window["f3"]);

// `const` declaration: Doesn't create property on global object, so
// "function, undefined"
const f4 = function() { /*...*/ };
result("const declaration", typeof f4, typeof window["f4"]);

// `class` declaration: Doesn't create property on global object, so
// "function, undefined"
class C1 {}
result("class declaration", typeof C1, typeof window["C1"]);

function setup() {
  document.body.insertAdjacentHTML(
    "beforeend",
    "<table>" +
    "<thead>" +
    "<tr><th>test</th><th>global</th><th>prop</th></tr>" +
    "</thead>" +
    "<tbody></tbody>" +
    "</table>"
  );
  return document.body.querySelector("tbody");
}

function result(label, direct, win) {
  tbody.insertAdjacentHTML(
    "beforeend",
    "<tr><td>" + [label, direct, win].join("</td><td>") + "</td></tr>"
  );
}
body {
  font-family: sans-serif;
}
table {
  border-collapse: collapse;
}
th, td {
  border: 1px solid #ddd;
  padding: 4px 8px;
}

在尖端浏览器上输出:

+----------------------+------------+-----------+
|         test         |   global   |   prop    |
+----------------------+------------+-----------+
| var declaration      |  function  | function  |
| function declaration |  function  | function  |
| let declaration      |  function  | undefined |
| const declaration    |  function  | undefined |
| class declaration    |  function  | undefined |
+----------------------+------------+-----------+

注意:有些转发器并未严格执行此操作,因此如果您在转换后的代码中看到不同的结果,请不要感到惊讶。

答案 5 :(得分:3)

使用eval:

myFunction = function(){};

var func_name = "myFunction";
var myFunctionPtr = eval(func_name);

答案 6 :(得分:3)

一种安全的方法是在测试其类型时对所谓的函数进行沙箱化:

function isFunction(expr) {
    function sandboxTemplate() {
        var window, document, alert; // etc.

        try {
            return typeof $expr$ == "function";
        } catch (e) {
            return false;
        }
    }

    try {
        var sandbox = new Function(
            sandboxTemplate.toString().replace("$expr$", expr)
            + "return sandboxTemplate()");
        return sandbox();
    } catch (e) {
        return false;
    }
}

function test(expr) {
    document.write("<div>\"" + expr + "\" <b>is "
        + (isFunction(expr) ? "" : "not ")
        + "</b>a function</div>");
}

/* Let's do some testing */

function realFunction() {
}

test("realFunction");       // exists!
test("notHere");            // non-existent
test("alert('Malicious')"); // attempt to execute malicious code!
test("syntax error {");     // attempt to blow us up!

输出:

  • “realFunction”一个功能
  • “notHere”不是功能
  • “alert('Malicious')”不是一项功能
  • “语法错误{”不是一个函数

沙盒代码可以用更简洁的方式编写,但我喜欢使用“模板”函数,而不是将JS代码嵌入到字符串文字中。

哦,如果不使用eval,这样做很好 - 尽管可以说使用Function构造函数与eval没有区别。

答案 7 :(得分:0)

找到该函数,然后调用它们

autoCallBack : function(_action){
            $(".module").each(function(){
                var modulName = $(this).attr("id");
                if( isFunction(modulName) ){
                    eval(modulName)();
                }
            });
        }

isFunction : function(_functionName){
        try {
            eval(_functionName);
        } catch (error) {
            return false;
        }
    return true;
}

答案 8 :(得分:0)

对于NodeJ

将您的函数写入单独的文件并导出它们并使用其名称引用来调用它们,如

//    functions.js
var funcOne = function(){
                   console.log('function ONE called')
              }
module.exports={
    //  name_exported : internal_name
    funcOne : funcOne
}

使用 index.js functions.js 中定义的函数:

//    index.js
var methods = require('./functions.js')   // path to functions.js
methods['funcOne']()

输出:

> node index.js
> function ONE called