【问题标题】:Testing if value is a function测试 value 是否是一个函数
【发布时间】:2010-10-22 08:25:42
【问题描述】:

我需要测试一个表单的onsubmit 的值是否是一个函数。格式通常为onsubmit="return valid();"。有没有办法判断这是否是一个函数,以及它是否可调用?使用 typeof 只是返回它是一个字符串,这对我没有多大帮助。

编辑:当然,我理解“return valid();”是一个字符串。我已经replaced 将其归结为“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() 不会触发现有的 onsubmits。

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;
    }
} );

关于如何更好地做到这一点的建议?

【问题讨论】:

    标签: javascript typeof onsubmit


    【解决方案1】:

    这样的简单检查会让您知道它是否存在/已定义:

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

    【讨论】:

    • 这行不通。当 onsubmit 也是一个非空字符串时,if 将断言为 TRUE。
    • 一种可怕的测试某物是否为函数的方法——如前所述,并且更清楚地说:任何“真实”都会导致该代码“做事”,而这可能不是预期的。如果 this.onsubmit 设置为 5 或 "hello" 或 JavaScript 中任何其他计算结果为 true 的值,您将获得意外行为。
    • 问题的主题是询问如何检查某物是否存在。这就是我的建议——不多也不少。
    • 并非如此 - 原始帖子指出他“需要测试表单的 onsubmit 的值是否是一个函数。”您的条件不是 this.onsubmit 是否是一个函数,您的测试只是询问 this.onsubmit 是否“真实”
    【解决方案2】:

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

    function x() { 
        console.log("hi"); 
    }
    
    typeof "x"; // returns "string"
    
    typeof x; // returns "function"
    

    【讨论】:

      【解决方案3】:

      你用的是什么浏览器?

      alert(typeof document.getElementById('myform').onsubmit);
      

      这给了我在 IE7 和 FireFox 中的“function”。

      【讨论】:

      • 即使你的 onsubmit 是“return valid();”?
      • 是的——别忘了,你不能在函数之外有“return”。
      • form.onsubmit 将始终是一个函数,只要它被定义为 HTML 属性。看我的回答。
      【解决方案4】:

      您可以尝试修改this technique 以满足您的需求:

       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.');
       }
      

      【讨论】:

        【解决方案5】:

        试试

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

        【讨论】:

        • 这只是一个示例。您可以将其更改为 button.onsubmit instanceof Function
        【解决方案6】:

        嗯,"return valid();"一个字符串,所以这是正确的。

        如果你想检查它是否附加了一个函数,你可以试试这个:

        formId.onsubmit = function (){ /* */ }
        
        if(typeof formId.onsubmit == "function"){
          alert("it's a function!");
        }
        

        【讨论】:

          【解决方案7】:

          如果它是一个字符串,你可以假设/希望它总是这种形式

          return SomeFunction(arguments);
          

          解析函数名,然后查看该函数是否使用

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

          【讨论】:

          • 我也正要添加这个分辨率...只要记住在文档/窗口级别注册函数
          【解决方案8】:
            if ( window.onsubmit ) {
               //
            } else {
               alert("Function does not exist.");
            }
          

          【讨论】:

            【解决方案9】:

            您可以简单地使用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 之外进行测试。
            【解决方案10】:

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

            在这种情况下,我不明白您是如何通过 typeof 操作获得字符串的。你应该提供更多细节,更好的一些代码。

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

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

            顺便说一句,您的代码不起作用,因为您的正则表达式将提取字符串“valid();”,这绝对不是一个函数。

            【讨论】:

              【解决方案11】:

              我认为混淆的根源在于节点的属性和对应的属性之间的区别。

              您正在使用:

              $("a.button").parents("form").attr("onsubmit")
              

              您正在直接读取onsubmit 属性的值(必须是一个字符串)。相反,您应该访问节点的onsubmit 属性

              $("a.button").parents("form").prop("onsubmit")
              

              这是一个快速测试:

              <form id="form1" action="foo1.htm" onsubmit="return valid()"></form>
              <script>
              window.onload = function () {
                  var form1 = document.getElementById("form1");
              
                  function log(s) {
                      document.write("<div>" + s + "</div>");
                  }
              
                  function info(v) {
                      return "(" + typeof v + ") " + v;
                  }
              
                  log("form1 onsubmit property: " + info(form1.onsubmit));
                  log("form1 onsubmit attribute: " + info(form1.getAttribute("onsubmit")));
              };
              </script> 
              

              这会产生:

              form1 onsubmit 属性:(function) function onsubmit(event) { return valid(); } form1 onsubmit 属性:(字符串)返回有效()

              【讨论】:

                【解决方案12】:

                我将提交按钮替换为 锚链接。自从打电话 form.submit() 没有激活 onsubmit 的,我正在找到它,并且 自己评估()。但我想 检查函数之前是否存在 只是评估()那里有什么。 – 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

                无论您是分配onsubmit HTML 属性还是在 JavaScript 中分配它,上述内容都应该有效:

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

                【讨论】:

                • f.onsubmit 中的 f 来自哪里?
                • f 是一个表单实例。您将它作为参数传递给 testOnsubmitAndSubmit 函数。 (我知道这个问题已经很老了,但也许我的回答会节省一些时间:))
                【解决方案13】:

                您始终可以使用 JavaScript 博客上的 typeOf 函数之一,例如 Chris West's。对typeOf() 函数使用如下定义是可行的:

                function typeOf(o){return {}.toString.call(o).slice(8,-1)}
                

                这个函数(在全局命名空间中声明,可以这样使用:

                alert("onsubmit is a " + typeOf(elem.onsubmit));
                

                如果是函数,则返回“函数”。如果是字符串,则返回“String”。其他可能的值显示为here

                【讨论】:

                  【解决方案14】:
                  // This should be a function, because in certain JavaScript engines (V8, for
                  // example, try block kills many optimizations).
                  function isFunction(func) {
                      // For some reason, function constructor doesn't accept anonymous functions.
                      // Also, this check finds callable objects that aren't function (such as,
                      // regular expressions in old WebKit versions), as according to EcmaScript
                      // specification, any callable object should have typeof set to function.
                      if (typeof func === 'function')
                          return true
                  
                      // If the function isn't a string, it's probably good idea to return false,
                      // as eval cannot process values that aren't strings.
                      if (typeof func !== 'string')
                          return false
                  
                      // So, the value is a string. Try creating a function, in order to detect
                      // syntax error.
                      try {
                          // Create a function with string func, in order to detect whatever it's
                          // an actual function. Unlike examples with eval, it should be actually
                          // safe to use with any string (provided you don't call returned value).
                          Function(func)
                          return true
                      }
                      catch (e) {
                          // While usually only SyntaxError could be thrown (unless somebody
                          // modified definition of something used in this function, like
                          // SyntaxError or Function, it's better to prepare for unexpected.
                          if (!(e instanceof SyntaxError)) {
                              throw e
                          }
                  
                          return false
                      }
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    使用基于字符串的变量作为示例并使用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();
                    }
                    

                    【讨论】:

                    • 你并不需要那个 fn 变量,你可以使用 window[value]();
                    • 是的,我知道,但我也意识到,长格式通常更容易理解,因为这主要是一个学习你的输入的网站,无论如何@LajosMeszaros 都很有价值
                    【解决方案16】:

                    typeof xxx === 'function'不是最好最快的吗?

                    与 instanceof 和 _underscore 相比,我做了一个长凳,你可以试试看

                    1. 它似乎比 instanceof 更快(使用 chrome)
                    2. 如果未定义变量,它不会引发错误

                    这里有一张长凳:https://jsbench.me/qnkf076cqb/1

                    【讨论】:

                      【解决方案17】:

                      注意 es6 类也是一个函数但不可调用

                      class C {}
                      
                      typeof C === "function"  // true
                      C instanceof Function    // true
                      
                      C()       // error
                      C.call()  // error
                      new C()   // okay
                      new C     // okay
                      

                      【讨论】:

                        【解决方案18】:

                        检查值上的call 方法似乎是一个足够好的测试。例如,val.call &amp;&amp; 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
                        

                        注意:除非是类。

                        【讨论】:

                        • 这也是我的首选方法。快速有效。只是来这里看看其他人如何处理它。认为我会坚持下去。
                        猜你喜欢
                        • 2011-04-13
                        • 2014-05-03
                        • 2016-11-16
                        • 1970-01-01
                        • 1970-01-01
                        • 2020-05-13
                        • 1970-01-01
                        • 2012-06-02
                        • 1970-01-01
                        相关资源
                        最近更新 更多