【问题标题】:Check if a variable is of function type检查变量是否为函数类型
【发布时间】:2011-08-25 09:26:38
【问题描述】:

假设我有任何变量,定义如下:

var a = function() {/* Statements */};

我想要一个函数来检查变量的类型是否类似于函数。即:

function foo(v) {if (v is function type?) {/* do something */}};
foo(a);

如何检查变量a 是否为上面定义的Function 类型?

【问题讨论】:

标签: javascript


【解决方案1】:
if (typeof v === 'function') {
    // do something
}

【讨论】:

  • 请注意typeof Objecttypeof Datetypeof String 等一些内容,它们也会返回'function'
  • @Dave,我不确定问题出在哪里,因为这些是函数。
  • if (v instanceOf Function)有什么区别?
  • @mquandalle 没有什么大的区别,除了instanceof 如果您正在检查来自另一个文档(可能是 iframe)的函数,它将不起作用。性能各不相同。
  • 与公认的答案不同,这也适用于异步函数。对于asyncfunctionToCheckgetType.toString.call(functionToCheck)==='[object AsyncFunction]' 其中typeof asyncfunctionToCheck === 'function'
【解决方案2】:

Underscore.js 使用更精细但性能更高的测试:

_.isFunction = function(obj) {
  return !!(obj && obj.constructor && obj.call && obj.apply);
};

见:http://jsperf.com/alternative-isfunction-implementations

编辑:更新的测试表明 typeof 可能更快,请参阅 http://jsperf.com/alternative-isfunction-implementations/4

【讨论】:

  • Underscore 的版本在大多数浏览器中速度要快得多。见:jsperf.com/alternative-isfunction-implementations
  • 我确实喜欢下划线,简单但功能强大。也就是说,可能值得注意的是,此实现可能会被具有这些属性的对象欺骗。
  • @PaulRosania 今天早些时候偶然发现了这些性能测试,updated them with verification plus more test data as revision 4 - 请运行它以增加浏览器测试覆盖率。它每秒的操作速度较慢(由于许多测试),但它也显示了一个实现差异(打开您的 javascript 控制台并重新加载页面,可能会记录错误消息)。注意:修订版 3 添加了 isFunctionD(仅基于 typeof == "function") - 它似乎比 Underscore 的“快速”版本快得多
  • 这个答案现在有点误导,因为 Underscore.js 现在在 revision 12 上,而不是上面引用的修订版 4,它对替代 isFunction() 实现的测试。它目前使用的东西非常接近dandean 的建议。
  • Underscore.js 现在使用typeof obj == 'function' || false。 (Source)
【解决方案3】:

当然 underscore 的方式更有效,但是当效率不是问题时,最好的检查方法是写在 @Paul Rosania 链接的 underscore 页面上。

受下划线启发,最终的isFunction函数如下:

function isFunction(functionToCheck) {
 return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}

注意:此解决方案不适用于异步函数、生成器或代理函数。请查看其他答案以获取更多最新解决方案。

【讨论】:

  • 可能有人对此事进行了更广泛的研究,但have a look at the results of revision 4 of the jsperf with simple "result verification"isFunctionA 显示了与其他方法相比的实现差异。
  • updated performance tests 看起来速度差异很大,具体取决于您的浏览器。在 Chrome 中,typeof(obj) === 'function' 似乎是迄今为止最快的;但是,在 Firefox 中,obj instanceof Function 显然是赢家。
  • 关于部分:typeof 应该只用于检查变量或属性是否未定义。A good use of typeof中的javascript.info/tutorial/type-detection > 部分和作者指出的以下部分,情况正好相反
  • Alex,我很好奇你为什么说 typeof 应该只用于检查未定义。顾名思义,它的目的是检查某物的类型,而不仅仅是它是否存在。使用它进行类型检查时是否会出现技术问题或问题,或者更多的是偏好?如果有警告,最好列出它们,这样其他人就可以避免绊倒它们。
  • 请继续滚动以找到更简单的解决方案。
【解决方案4】:

@grandecomplex:您的解决方案相当冗长。这样写会更清楚:

function isFunction(x) {
  return Object.prototype.toString.call(x) == '[object Function]';
}

【讨论】:

  • Object.prototype.toString.call 对于您感兴趣的其他 javascript 类型很有用。您甚至可以检查 null 或 undefined,这使得它非常强大。
  • 这个答案需要更多的支持,因为它是目前最准确的
【解决方案5】:

试试instanceof 运算符:似乎所有函数都继承自Function 类:

// Test data
var f1 = function () { alert("test"); }
var o1 = { Name: "Object_1" };
F_est = function () { };
var o2 = new F_est();

// Results
alert(f1 instanceof Function); // true
alert(o1 instanceof Function); // false
alert(o2 instanceof Function); // false

【讨论】:

  • 正如在别处指出的那样,如果函数来自另一个文档(例如 iframe),这可能会失败,因为每个文档都有自己单独的 Function
【解决方案6】:

我发现在IE8中测试原生浏览器功能时,使用toStringinstanceoftypeof不起作用。这是一种在 IE8 中运行良好的方法(据我所知):

function isFn(f){
    return !!(f && f.call && f.apply);
}
//Returns true in IE7/8
isFn(document.getElementById);

或者,您可以使用以下方法检查本机函数:

"getElementById" in document

不过,我在某处读到这在 IE7 及更低版本中并不总是有效。

【讨论】:

    【解决方案7】:

    有好几种方法,我总结一下

    1. 最好的方法是: function foo(v) {if (v instanceof Function) {/* 做某事 */} }; 最高效(无字符串比较)和优雅的解决方案 - instanceof 运算符在浏览器中支持很长时间了,所以不用担心 - 它可以在 IE 6 中使用。
    2. 下一个最佳方法是: function foo(v) {if (typeof v === "function") {/* 做某事 */} }; typeof 的缺点是它很容易出现静默故障,很糟糕,所以如果你有错字(例如“finction”)——在这种情况下,`if` 只会返回 false,你不会知道你有错误直到稍后在您的代码中
    3. 下一个最好的方法是: 功能是功能(功能检查){ 变量 getType = {}; return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; } 这与解决方案 #1 或 #2 相比没有优势,但可读性要差得多。一个改进的版本是 函数是函数(x){ 返回 Object.prototype.toString.call(x) == '[object Function]'; } 但仍然比解决方案#1 少很多语义

    【讨论】:

    • 如果函数传递到不同的帧上下文,第一个解决方案会失败。例如,来自 iframe top.Function !== Function。可以肯定的是,请使用第二个(希望在调试期间更正“function”的任何拼写错误)。
    • 关于您关于拼写错误的观点:任何有此拼写错误的代码都可能很快失败/不会比任何其他基于拼写错误的错误更明显。 typeof === "function" 是最干净的解决方案。此外,您使用 instanceof 的“最佳”解决方案不考虑多个全局变量,例如跨帧检查,并且可能返回假阴性。
    • 错字的故事只是提到了魔法弦的危害。尽可能避免使用魔术字符串。
    【解决方案8】:

    你应该在js中使用typeOf操作符

    var a=function(){
        alert("fun a");
    }
    alert(typeof a);// alerts "function"
    

    【讨论】:

      【解决方案9】:

      jQuery(3.3 版后已弃用)Reference

      $.isFunction(functionName);
      

      AngularJS Reference

      angular.isFunction(value);
      

      Lodash Reference

      _.isFunction(value);
      

      下划线 Reference

      _.isFunction(object); 
      

      Node.js 自 v4.0.0 起已弃用 Reference

      var util = require('util');
      util.isFunction(object);
      

      【讨论】:

        【解决方案10】:

        另一种简单的方法:

        var fn = function () {}
        if (fn.constructor === Function) {
          // true
        } else {
          // false
        }
        

        【讨论】:

        • 如果 fn 未定义,则会抛出错误
        • fn && fn.constructor === Function 这个怎么样?
        【解决方案11】:

        从 node v0.11 开始,您可以使用标准的 util 功能:

        var util = require('util');
        util.isFunction('foo');
        

        【讨论】:

        • util.isFunction 已弃用
        【解决方案12】:

        以下似乎也适用于我(从node.js 测试):

        var isFunction = function(o) {
             return Function.prototype.isPrototypeOf(o);
        };
        
        console.log(isFunction(function(){})); // true
        console.log(isFunction({})); // false
        

        【讨论】:

          【解决方案13】:

          var foo = function(){};
          if (typeof foo === "function") {
            alert("is function")
          }

          【讨论】:

          • ...和(() => (typeof obj === 'function') && doSomething()) 仍然是最快的选择。
          【解决方案14】:

          我认为您可以在 Function 原型上定义一个标志并检查您要测试的实例是否继承了该标志

          定义一个标志:

          Function.prototype.isFunction = true; 
          

          然后检查是否存在

          var foo = function(){};
          foo.isFunction; // will return true
          

          缺点是另一个原型可以定义相同的标志,然后它毫无价值,但如果你完全控制包含的模块,这是最简单的方法

          【讨论】:

          • 如果 foo 未定义,它将失败并出现错误。更不用说你修改了原生原型,这是完全错误的。
          【解决方案15】:

          如果您使用 Lodash,您可以使用 _.isFunction

          _.isFunction(function(){});
          // => true
          
          _.isFunction(/abc/);
          // => false
          
          _.isFunction(true);
          // => false
          
          _.isFunction(null);
          // => false
          

          如果 value 是函数,则此方法返回 true,否则返回 false

          【讨论】:

            【解决方案16】:

            对于那些对函数式风格感兴趣,或者希望在元编程中使用更具表现力的方法(例如类型检查)的人来说,看看Ramda 库来完成这样的任务可能会很有趣。

            接下来的代码只包含纯函数和无点函数:

            const R = require('ramda');
            
            const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);
            
            const equalsSyncFunction = isPrototypeEquals(() => {});
            
            const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);
            

            从 ES2017 开始,async 函数可用,因此我们也可以检查它们:

            const equalsAsyncFunction = isPrototypeEquals(async () => {});
            
            const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);
            

            然后将它们组合在一起:

            const isFunction = R.either(isSyncFunction, isAsyncFunction);
            

            当然,函数应该受到nullundefined 值的保护,以便使其“安全”:

            const safeIsFunction = R.unless(R.isNil, isFunction);
            

            并且,完成sn-p总结:

            const R = require('ramda');
            
            const isPrototypeEquals = R.pipe(Object.getPrototypeOf, R.equals);
            
            const equalsSyncFunction = isPrototypeEquals(() => {});
            const equalsAsyncFunction = isPrototypeEquals(async () => {});
            
            const isSyncFunction = R.pipe(Object.getPrototypeOf, equalsSyncFunction);
            const isAsyncFunction = R.pipe(Object.getPrototypeOf, equalsAsyncFunction);
            
            const isFunction = R.either(isSyncFunction, isAsyncFunction);
            
            const safeIsFunction = R.unless(R.isNil, isFunction);
            
            // ---
            
            console.log(safeIsFunction( function () {} ));
            console.log(safeIsFunction( () => {} ));
            console.log(safeIsFunction( (async () => {}) ));
            console.log(safeIsFunction( new class {} ));
            console.log(safeIsFunction( {} ));
            console.log(safeIsFunction( [] ));
            console.log(safeIsFunction( 'a' ));
            console.log(safeIsFunction( 1 ));
            console.log(safeIsFunction( null ));
            console.log(safeIsFunction( undefined ));
            

            但是,请注意,由于大量使用高阶函数,此解决方案的性能可能低于其他可用选项。

            【讨论】:

              【解决方案17】:

              具有更多浏览器支持并且还包括异步功能的东西可能是:

              const isFunction = value => value && (Object.prototype.toString.call(value) === "[object Function]" || "function" === typeof value || value instanceof Function);
              

              然后像这样测试它:

              isFunction(isFunction); //true
              isFunction(function(){}); //true
              isFunction(()=> {}); //true
              isFunction(()=> {return 1}); //true
              isFunction(async function asyncFunction(){}); //true
              isFunction(Array); //true
              isFunction(Date); //true
              isFunction(Object); //true
              isFunction(Number); //true
              isFunction(String); //true
              isFunction(Symbol); //true
              isFunction({}); //false
              isFunction([]); //false
              isFunction("function"); //false
              isFunction(true); //false
              isFunction(1); //false
              isFunction("Alireza Dezfoolian"); //false
              

              【讨论】:

                【解决方案18】:

                注意这一点:

                typeof Object === "function" // true.
                typeof Array  === "function" // true
                

                【讨论】:

                • ObjectArray 都是构造函数,尽管它们共享一些您可能想要使用的静态方法,但几乎不可能有人会这样检查它们的类型。有没有可能发生的原因?除了程序员的错误,我目前无法提出任何建议。
                【解决方案19】:

                如果您正在寻找简单的解决方案:

                 function isFunction(value) {
                   return value instanceof Function
                }
                

                【讨论】:

                  猜你喜欢
                  • 2020-03-21
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-07-09
                  • 1970-01-01
                  相关资源
                  最近更新 更多