提出以下情况:
function functionExists(functionName) {
if (typeof window[functionName] == 'function') console.log("It's a function");
}
Run Code Online (Sandbox Code Playgroud)
什么是在同等功能nodejs
的functionExists
那里是没有全局window
变量?
具体情况:
我的具体情况使用了webpack
而不是nodejs
,但基本上问题是一样的。我可以window
在这里使用,但是干净地实现所有内容会太复杂,并且不建议webpack
将事情减轻到window
全局变量。
基本上,我有一个PHP
后端,它生成一个 html <form>
,通过一个data
属性向它添加一些选项。当页面加载时,我的 javascript 会初始化它<form>
并为其提供一系列功能(例如验证)。javascript 对这个表单所做的另一件事是它解析它的数据属性,而不是正常的页面重新加载提交,它改变了表单,以便它通过ajax
请求提交给服务器。
当这个提交发生时,它被设置,按钮和整个表单被禁用,直到我的Ajax
脚本发回响应。这是如何完成的,是我有一个Project_Form
类,当它初始化时,将自身附加到jQuery
提交事件,停止基本提交事件,并运行一个内部函数,该函数将 ajax 请求发送到 api 方法。设置了 ajax 请求,当收到响应时,同一个实例化类将收到此响应,因此我可以继续使用它。
当表单收到响应时,它必须对它做一些事情。在最基本的情况下,它必须向用户显示成功消息,但还有一些更复杂的情况,例如,它必须进行页面重定向(例如登录表单)。现在,它被设置为默认情况下,它将显示一条消息,但是当我在 PHP 中定义此表单时,我可以选择“劫持”此默认行为,而不是将 ajax 响应发送到一个自定义函数,它将专门解决这种情况。
当我在 PHP 中渲染表单时,我已经知道表单应该在哪里发送成功响应(到哪个 javascript 函数),但我只能通过字符串将此信息提供给 javascript。所以我的Project_Form
班级应该获取这个字符串,并且应该尝试从中获取一个它将使用的函数。这就是我的问题的来源。
除非你特别知道这是一个全局函数(在 nodejs 中几乎从来没有这种情况),默认情况下,nodejs 中的函数范围是模块,没有办法像你在window
对象中那样通过字符串名称查找它们浏览器,就像无法在 Javascript 中的函数内按名称查找局部变量一样。
通常,不要通过字符串名称传递函数。或者,如果必须,那么您需要创建一个查找表,您可以根据该表检查函数名称。
我建议你在这里解释你试图解决的真正问题,因为通过字符串名称传递函数不是你通常想要做的事情。
有一点使用eval()
可以查看字符串是否表示范围内的函数名称:
// Warning, you must know that the argument f (if it is a string) does not
// contain harmful Javascript code because it will be used with eval()
function isFunction(f) {
// if already a function reference
if (typeof f === "function") {
return true;
// see if string represents a function name somewhere in scope
} else if (typeof f === "string") {
try {
return eval(`typeof ${f} === "function"`);
} catch(e) {
return false;
}
} else {
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
注意:这会测试函数是否在函数的范围内isFunction()
。如果要测试它是否在当前范围内,则需要执行以下操作:
eval(`typeof ${f} === "function"`)
Run Code Online (Sandbox Code Playgroud)
内联在您当前的范围内,以便它在您要从中进行查找的范围内运行。
要考虑使用它,您必须知道字符串的来源是安全的,并且不能包含有害代码。但是,正如我之前所说,最好以不同的方式设计您的程序,这样您就不会通过字符串名称来引用函数。
而且,这是一个可运行的代码片段,显示它的实际运行情况(也适用于 node.js 模块):
// Warning, you must know that the argument f (if it is a string) does not
// contain harmful Javascript code because it will be used with eval()
function isFunction(f) {
// if already a function reference
if (typeof f === "function") {
return true;
// see if string represents a function name somewhere in scope
} else if (typeof f === "string") {
try {
return eval(`typeof ${f} === "function"`);
} catch(e) {
return false;
}
} else {
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
问题编辑后添加更多
如果您只将函数名称作为字符串,并且它指向的函数不是某个已知对象的属性,那么我所知道的将该字符串转换为函数引用的唯一方法是使用eval()
.
您可以直接使用eval()
例如执行它,eval(functionName + "()")
或者您可以获得对该函数的引用eval("let fn = " + functionName)
,然后使用新定义的fn
变量来调用该函数。
如果您控制可以引用的各种函数(因为它们是您的 Javascript),那么您可以使所有这些函数成为您的 Javsacript 中已知对象的属性:
const functionDispatcher = {
function1,
function2,
function3,
function4
}
Run Code Online (Sandbox Code Playgroud)
然后,而不是使用eval()
,您可以functionDispatcher
像之前引用的那样从对象中引用它们window
(除非这不是全局的),如下所示:
functionDispatcher[someFunctionName]();
Run Code Online (Sandbox Code Playgroud)
这将是比 using 更好的选择,eval()
因为通过不安全的字符串插入随机代码的风险较小。