如何将字符串转换为 JavaScript 函数调用? [复制]

Posted

技术标签:

【中文标题】如何将字符串转换为 JavaScript 函数调用? [复制]【英文标题】:How to turn a String into a JavaScript function call? [duplicate] 【发布时间】:2010-10-29 02:17:27 【问题描述】:

我得到了一个类似的字符串:

settings.functionName + '(' + t.parentNode.id + ')';

我想翻译成这样的函数调用:

clickedOnItem(IdofParent);

这当然必须在 javascript 中完成。当我对settings.functionName + '(' + t.parentNode.id + ')'; 发出警报时,似乎一切都正确。我只需要调用它会转换成的函数。

传说:

settings.functionName = clickedOnItem

t.parentNode.id = IdofParent

【问题讨论】:

settings.functionName是什么类型? 【参考方案1】:

看来我讨厌eval,我是not alone:

var fn = window[settings.functionName];
if(typeof fn === 'function') 
    fn(t.parentNode.id);

编辑: 回复@Mahan 的评论: 在这种特殊情况下,settings.functionName 将是 "clickedOnItem"。这将在运行时将var fn = window[settings.functionName]; 转换为var fn = window["clickedOnItem"],从而获得对function clickedOnItem (nodeId) 的引用。一旦我们在一个变量中引用了一个函数,我们就可以通过“调用变量”来调用这个函数,即fn(t.parentNode.id),它等于clickedOnItem(t.parentNode.id),这正是OP想要的。

更完整的例子:

/* Somewhere: */
window.settings = 
  /* [..] Other settings */
  functionName: 'clickedOnItem'
  /* , [..] More settings */
;

/* Later */
function clickedOnItem (nodeId) 
  /* Some cool event handling code here */


/* Even later */
var fn = window[settings.functionName]; 
/* note that settings.functionName could also be written
   as window.settings.functionName. In this case, we use the fact that window
   is the implied scope of global variables. */
if(typeof fn === 'function') 
    fn(t.parentNode.id);

【讨论】:

鉴于原始问题,我认为“if(typeof...”代码不正确。只需调用 window[settings.functionName](t.parentNode.id)。你会得到如果函数不存在,则出现 TypeError,这比默默地吞下问题并且什么都不调用要好。 但是如果函数不在全局(窗口)范围内怎么办? 查看我的 awnser 以获取从字符串中检索函数的通用方法,即使在多个闭包中也是如此。如果您想在 DOM 属性中注册回调,这是理想的选择。 @uptownhr window.settings.functionName 确实如此。 window[window.settings.functionName] 现在可以了。在 javascript 中,可以使用字符串访问对象成员,就像使用数组一样。假设你的函数是在全局范围内声明的,它就变成了 window 对象中的一个函数。您可以使用字符串调用它。 如果没有“我讨厌 eval”,似乎在政治上是错误的。 node.js 和表达式字符串来自数据库的最佳方法是什么?【参考方案2】:
window[settings.functionName](t.parentNode.id);

不需要 eval()

【讨论】:

不错。当然,这是假设函数没有在不同的范围内声明,但即使那样我想你也可以在那个范围内做到这一点...... 如果想要的函数在全局范围内就可以使用,如果不在,则用函数的范围替换window。 运行良好。甚至比 eval 函数调用使用的代码更少。 很高兴看到另一个人尽可能避免评估。 虽然在闭包代码中不起作用。 (function())();【参考方案3】:

这是一种更通用的方法,同时支持范围:

// Get function from string, with or without scopes (by Nicolas Gauthier)
window.getFunctionFromString = function(string)

    var scope = window;
    var scopeSplit = string.split('.');
    for (i = 0; i < scopeSplit.length - 1; i++)
    
        scope = scope[scopeSplit[i]];

        if (scope == undefined) return;
    

    return scope[scopeSplit[scopeSplit.length - 1]];

希望它可以帮助一些人。

【讨论】:

很好,我使用了多个作用域的 WinJS.Namespace.define(),感谢您,我能够从中动态调用随机函数。 +1 使它在任何范围内都能工作。我正在使用 TypeScript,并设置“scope=this”来访问我班级中的函数。完美运行! 为我工作。谢谢 NGauthier 花了将近半天的时间在谷歌上搜索答案。这是一个很棒的解决方案! +1【参考方案4】:

JavaScript 有一个 eval 函数,它计算字符串并将其作为代码执行:

eval(settings.functionName + '(' + t.parentNode.id + ')');

【讨论】:

我可以否决它以在适当的情况下使用 eval。这里不需要评估。最好将函数作为对象的属性来查找。 eval 很慢,有点像用大锤拍苍蝇。 看机器回答。 eval 是一个常见的成语。如果你不喜欢它,你可能会普遍讨厌 Javascript。恕我直言, eval 是这里的正确答案。如果您删除 if-typedef 检查,机器的答案是可以的,但它会无缘无故地添加代码。如果您传递的字符串有问题,那么无论哪种情况都有问题。 你们是一群追随一句押韵的名言的追随者。如果你问这些“eval 是邪恶的”人中的任何一个,为什么如果他们不跑到谷歌上它实际上是邪恶的,你将得不到任何答案。这是绵羊编程的经典例子。如果您不理解它,请保持沉默并研究。 Eval 并不“邪恶”,但它可能很慢而且肯定不安全。【参考方案5】:

eval() 是您需要执行此操作的函数,但我建议尝试其中一种方法以尽量减少 eval 的使用。希望其中之一对您有意义。

存储函数

将函数存储为函数,而不是字符串,稍后将其用作函数。函数的实际存储位置取决于您。

var funcForLater = clickedOnItem;

// later is now
funcForLater(t.parentNode.id);

someObject.funcForLater = clickedOnItem;    
// later is now    
(someObject.funcForLater)(t.parentNode.id);

存储函数名称

即使你必须将函数名存储为字符串,你也可以通过这样做来最小化复杂性

(eval(settings.functionName))(t.parentNode.id);

最大限度地减少您必须构建和评估的 Javascript 数量。

处理程序字典

将您可能需要的所有操作函数放入一个对象中,并使用字符串将它们称为字典样式。

// global
itemActions =  click: clickedOnItem, rightClick: rightClickedOnItem /* etc */ ;

// Later...
var actionName = "click"; // Or wherever you got the action name
var actionToDo = itemActions[actionName];
actionToDo(t.parentNode.id);

(次要注意:如果您在此处使用语法 itemActions[actionName](t.parentNode.id);,则该函数将作为 itemActions 的方法调用。)

【讨论】:

我真的很喜欢字典处理方法——对我来说效果很好——谢谢。【参考方案6】:

虽然我喜欢第一个答案并且讨厌 eval,但我想补充一点,还有另一种方法(类似于 eval),所以如果你可以绕过它而不使用它,你最好这样做。但在某些情况下,您可能希望在某些 ajax 调用之前或之后调用一些 javascript 代码,如果您在自定义属性中而不是 ajax 中有此代码,则可以使用:

    var executeBefore = $(el).attr("data-execute-before-ajax");
    if (executeBefore != "") 
        var fn = new Function(executeBefore);
        fn();
    

如果您可能需要多次调用它,或者最终将其存储在函数缓存中。

再一次 - 如果您有其他方法,请不要使用 eval 或此方法。

【讨论】:

函数构造函数是Eval的一种形式jslinterrors.com/the-function-constructor-is-eval 是的,它们相似,但不相同。 “new Function() 将存储在字符串中的 JavaScript 代码解析为函数对象,然后可以调用该函数对象。它无法访问局部变量,因为代码在单独的范围内运行。”【参考方案7】:

如果settings.functionName 已经是一个函数,你可以这样做:

settings.functionName(t.parentNode.id);

否则,如果 settings.functionName 只是函数的名称,这也应该有效:

if (typeof window[settings.functionName] == "function") 
    window[settings.functionName](t.parentNode.id);

【讨论】:

【参考方案8】:

我希望能够将函数名作为字符串,调用它,并将参数传递给函数。我无法得到这个问题的选定答案,但answer 准确地解释了它,这里有一个简短的演示。

function test_function(argument)    
    alert('This function ' + argument); 


functionName = 'test_function';

window[functionName]('works!');

这也适用于多个参数。

【讨论】:

【参考方案9】:

我花了一段时间才弄清楚,因为传统的 window['someFunctionName']() 起初对我不起作用。我的函数名称作为 AJAX 响应从数据库中提取。此外,无论出于何种原因,我的函数被声明在窗口范围之外,所以为了解决这个问题,我不得不重写我调用的函数

function someFunctionName() 

window.someFunctionName = function() 

从那里我可以轻松地致电window['someFunctionName']()。我希望这对某人有帮助!

【讨论】:

见his answer下方Fabien Ménager的评论 -> “如果你的函数不在全局范围内,请将window替换为函数的范围。” 请更新您的答案(您可以提供该问题作为补充)干杯;)【参考方案10】:

我更喜欢使用这样的东西:

window.callbackClass['newFunctionName'] = function(data)  console.log(data) ;
...
window.callbackClass['newFunctionName'](data);

【讨论】:

欢迎来到 ***。对原因有更多的解释会很棒。看看“callbackClass”是否是“window”的标准成员,这已经引起了轰动,但现在我猜你只是想避免污染窗口命名空间。 示例中的 callbackClass 是添加到非内置窗口对象的新属性名称。所以汤姆正在设置一个指向函数的窗口变量。【参考方案11】:

基于 Nicolas Gauthier 的回答:

var strng = 'someobj.someCallback';
var data = 'someData';

var func = window;
var funcSplit = strng.split('.');
for(i = 0;i < funcSplit.length;i++)
   //We maybe can check typeof and break the bucle if typeof != function
   func = func[funcSplit[i]];

func(data);

【讨论】:

【参考方案12】:

在使用 CommonJS 规范的 javascript 中,例如 node.js,您可以执行我在下面显示的操作。这对于通过字符串访问变量非常方便,即使它没有在window 对象上定义。如果有一个名为 MyClass 的类,在名为 MyClass.js 的 CommonJS 模块中定义

// MyClass.js
var MyClass = function() 
    // I do stuff in here. Probably return an object
    return 
       foo: "bar"
    


module.exports = MyClass;

然后,您可以从另一个名为 MyOtherFile.js 的文件中执行此操作。

// MyOtherFile.js

var myString = "MyClass";

var MyClass = require('./' + myString);
var obj = new MyClass();

console.log(obj.foo); // returns "bar"

CommonJS 如此令人愉悦的另一个原因。

【讨论】:

【参考方案13】:
eval("javascript code");

在处理JSON时被广泛使用。

【讨论】:

Eval 是邪恶的...... Eval 是不安全和邪恶的,它是宇宙中所有不人道的根源,它是孤儿背后的原因 Eval 既慢又不安全。请参阅我的 awnser 以获取甚至支持范围的无 eval 通用解决方案(即:“module.submodule.function”)。在大量使用 JSON 和 AJAX 的应用程序中工作就像一个魅力...... “不安全和邪恶,它是宇宙中所有不人道的根源”我确实经常看到这一点,但是当 javascript 分发到您的浏览器时,“不安全”部分真的让我感到(始终可见)以及何时我们可以修改任何页面上的任何 html 或 JAVASCRIPT。我不使用 eval,但是说它不安全是没有意义的,因为它是 JAVASCRIPT 的。只有安全的 js 是服务器端 js,使用它可能会出现问题,但在前端任何东西都可以修改。 @Grep 谢谢! “eval is evil”是一个古老的谎言。您的所有客户端 javascript 都以字符串的形式传递给客户端,然后对其进行评估。普通页面加载和 eval("1+1") 之间的唯一区别是评估的时间。如果我的服务器受到严重破坏以至于它正在分发有问题的 javascript,我很难相信入侵者会触摸 eval 函数,因为它会毫无意义。

以上是关于如何将字符串转换为 JavaScript 函数调用? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何将 javascript 对象转换成 json字符串

如何在 JavaScript 中使用字节数组将字符串转换为 base64 编码?

Javascript函数 - 将字符串参数转换为运算符

如何将 javascript Date() 转换为 COleDateTime

编程:将一个数字字符串转换成一个整数(不得调用C语言提供的将字符串转换为整数的函数)。

将 QJsonObject 转换为 Javascript 对象