如何将字符串转换为 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 属性中注册回调,这是理想的选择。 @uptownhrwindow.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 中使用字节数组将字符串转换为 base64 编码?
如何将 javascript Date() 转换为 COleDateTime