测试值是否为函数

106
我需要测试一个表单的 onsubmit 值是否为函数。通常格式为 onsubmit="return valid();"。有没有办法判断它是不是一个函数并且它是否可调用?使用 typeof 只会返回字符串,这对我帮助不大。 编辑: 当然,我知道 "return valid();" 是字符串。我已将其替换为 "valid();",甚至是 "valid()"。我想知道这两个是否是函数。 编辑: 下面是一些代码,可能有助于说明我的问题:
$("a.button").parents("form").submit(function() {
    var submit_function = $("a.button").parents("form").attr("onsubmit");
    if ( submit_function && typeof( submit_function.replace(/return /,"") ) == 'function' ) {
        return eval(submit_function.replace(/return /,""));
    } else {
        alert("onSubmit is not a function.\n\nIs the script included?"); return false;
    }
} );

编辑 2:这是新代码。看起来我仍然需要使用 eval,因为调用 form.submit() 不会触发现有的 onsubmit。

var formObj = $("a.button").parents("form");
formObj.submit(function() {
    if ( formObj[0].onsubmit && typeof( formObj.onsubmit ) == 'function' ) {
        return eval(formObj.attr("onsubmit").replace(/return /,""));
    } else {
        alert("onSubmit is not a function.\n\nIs the script included?");
        return false;
    }
} );

有可能更好的做法吗?

18个回答

102
我正在用一个锚链接替换一个提交按钮。由于调用form.submit()不会激活onsubmit,所以我自己找到它并eval()执行它。但是在eval()执行之前,我想先检查这个函数是否存在。 - gms8994
<script type="text/javascript">
function onsubmitHandler() {
    alert('running onsubmit handler');
    return true;
}
function testOnsubmitAndSubmit(f) {
    if (typeof f.onsubmit === 'function') {
        // onsubmit is executable, test the return value
        if (f.onsubmit()) {
            // onsubmit returns true, submit the form
            f.submit();
        }
    }
}
</script>

<form name="theForm" onsubmit="return onsubmitHandler();">
<a href="#" onclick="
    testOnsubmitAndSubmit(document.forms['theForm']);
    return false;
"></a>
</form>

编辑:函数testOnsubmitAndSubmit中缺少参数f。

无论您是在HTML属性中分配onsubmit还是在JavaScript中分配它,上述代码应该都能起作用:

document.forms['theForm'].onsubmit = onsubmitHandler;

1
f.onsubmit中的f来自哪里? - Art
f 是一个表单实例。您将其作为参数传递给 testOnsubmitAndSubmit 函数。(我知道这个问题很老了,但也许我的回答能节省某些人的时间 :) ) - zeroos

75

尝试

if (this.onsubmit instanceof Function) {
    // do stuff;
}

7
那只是一个示例。你可以将其更改为 button.onsubmit 是一个函数实例。 - artemb

14

您可以简单地使用typeof运算符以及三元运算符进行缩写:

onsubmit="return typeof valid =='function' ? valid() : true;"
如果它是一个函数,我们就调用它并返回其返回值,否则只返回true 编辑: 我不确定你想做什么,但我会尝试解释可能发生的事情。
当你在html中声明你的onsubmit代码时,它会被转换为一个函数,因此可以从JavaScript "世界"中调用。这意味着这两种方法是等效的:
HTML: <form onsubmit="return valid();" />
JavaScript: myForm.onsubmit = function() { return valid(); };
这两个都将成为函数并且都可以被调用。你可以使用typeof运算符测试其中任何一个,它应该会产生相同的结果:"function"
现在,如果你通过JavaScript将字符串赋值给"onsubmit"属性,它仍然是一个字符串,因此无法调用。请注意,如果你对其应用typeof运算符,你将得到"string"而不是"function"
我希望这可能会澄清一些事情。再次强调,如果你想知道这样的属性(或任何标识符)是否是函数并且可调用,typeof运算符应该可以解决这个问题。尽管我不确定它是否可以在多个框架之间正常工作。
干杯

我需要在 onsubmit 之外测试这个。 - Glen Solsberry

5
你使用的是什么浏览器?
alert(typeof document.getElementById('myform').onsubmit);

这段文字在IE7和FireFox中显示为“function”。

即使您的 onsubmit 是 "return valid();"? - Glen Solsberry
1
是的 - 别忘了,你不能在函数外使用“return”。 - Greg
只要将form.onsubmit定义为HTML属性,它就会始终是一个函数。请参阅我的回答。 - Ionuț G. Stan

4

检查值的call方法似乎是一个足够好的测试。例如,val.call && val()

> a = () => {}
[Function: a]
> function b() {}
undefined
> c = function(){}
  [Function: c]
> d = 2
2
> e = []
  []
> f = {}
{}
> a.call
  [Function: call]
> b.call
  [Function: call]
> c.call
  [Function: call]
> d.call
undefined
> e.call
undefined
> f.call
undefined

注意:除非它是一个类。

1
这也是我的首选方法。快速而有效。我来这里只是想看看别人是如何处理的。我想我会坚持使用这种方法。 - Besworks

4

以字符串变量为例,利用 instanceof Function 进行操作。首先注册函数,然后将其赋值给变量,检查该变量是否为函数名,进行预处理,将函数赋值给新变量,最后调用该函数。

function callMe(){
   alert('You rang?');
}

var value = 'callMe';

if (window[value] instanceof Function) { 
    // do pre-process stuff
    // FYI the function has not actually been called yet
    console.log('callable function');
    //now call function
   var fn = window[value];
   fn();
}

2
你其实不需要那个fn变量,你可以直接使用windowvalue; - Lajos Mészáros
1
是的,我知道,但我也意识到长格式通常更容易理解,而且由于这主要是一个学习网站,无论如何都很重视您的输入。@LajosMeszaros - CrandellWS

3

请确保您在实际函数上调用 typeof,而不是字符串字面量:

function x() { 
    console.log("hi"); 
}

typeof "x"; // returns "string"

typeof x; // returns "function"

3
你可以尝试修改这个技巧以满足你的需求:
 function isFunction() {
   var functionName = window.prompt('Function name: ');
   var isDefined = eval('(typeof ' + functionName + '==\'function\');');
   if (isDefined)
     eval(functionName + '();');
   else
     alert('Function ' + functionName + ' does not exist');
 }
 function anotherFunction() {
   alert('message from another function.');
 }

2
如果它是一个字符串,你可以假设/希望它总是以下格式:
return SomeFunction(arguments);

解析函数名称,并查看该函数是否使用定义

if (window[functionName]) { 
    // do stuff
}

我正要添加这个分辨率...只需记得在文档/窗口级别注册函数。 - CrandellWS

2

当作为HTML表单元素属性定义时,form.onsubmit总是一个函数。它是附加到HTML元素的某种匿名函数,该函数将"this"指针绑定到该FORM元素,并且还具有一个名为"event"的参数,其中包含关于提交事件的数据。

在这些情况下,我不明白您如何从typeof操作中获得字符串结果。您应该提供更多详细信息,最好附上一些代码。

编辑(作为对您第二次编辑的回应):

我相信附加到HTML属性的处理程序将执行,而不管上面的代码。此外,您可以尝试以某种方式停止它,但似乎FF 3、IE 8、Chrome 2和Opera 9首先执行HTML属性处理程序,然后才执行附加的处理程序(我没有使用jQuery进行测试,而是使用addEventListener和attachEvent)。那么...您究竟想达到什么目的呢?

顺便说一下,您的代码无法正常工作,因为您的正则表达式将提取字符串"valid();",这显然不是一个函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接