【问题标题】:How to determine if a JavaScript function is defined?如何确定是否定义了 JavaScript 函数?
【发布时间】:2012-05-04 12:53:49
【问题描述】:

我想检查一个函数是否已定义(我不在乎如何,我的意思是它是可调用的)

示例代码:

var functions = {
    'alert':'alert',
    'undefinedFunction':'undefinedFunction',
    'ff.showAlert':'ff.showAlert'
};

var ff = {
    showAlert: function() {
        alert('the function works');
    }
};

for (i in functions) {
    console.log(i+' : '+typeof window[functions [i]]);
}

返回:

alert : function
undefinedFunction : undefined
ff.showAlert : undefined

console.log(typeof window.ff.showAlert); return function

Live demo
有没有办法以编程方式检查函数是否存在?

【问题讨论】:

标签: javascript


【解决方案1】:

代码:

window[functions [i]]

正在检查window['ff.showAlert'],但您真正要检查的是:

window['ff']['showAlert']

window.ff.showAlert

为此,需要遍历命名空间(window->ff->...):

function methodIsDefined(fn, obj) {
  var ns = fn.split('.');
  fn = ns.pop();
  do {
    if (!ns[0]) {
      return typeof obj[fn] === 'function';
    }
  } while(obj = obj[ns.shift()]);
  return false;
}

例如

methodIsDefined('ff.showAlert', window); // => true
methodIsDefined('ff.foo', window); // => false

【讨论】:

    【解决方案2】:

    您的问题在于命名空间。字符串"ff.showAlert" 没有引用函数window['ff']['showAlert'],而是引用window['ff.showAlert'],这是一个重要的区别。您声明的函数实际上是由window['ff']['showAlert'] 引用的。因此,您正在检查其存在的地方是错误的。

    如果您想检查此类命名空间函数的存在,您首先必须拆分字符串,然后遍历 DOM 以找到正确的属性。代码将类似于以下内容(未经测试!):

    function checkFunction( name ) {
    
      var path = "ff.showAlert".split( '.' ),
          runner = window;
    
      for( var i=0; i<path.length; i++ ) {
        if( path[i] in runner ) {
          runner = runner[ path[i] ];
        } else {
          return false;
        }
      }
      return runner;
    }
    

    编辑

    正如@VirtualBlackFox 在 cmets 中指出的那样:上述解决方案仅在函数声明在window-范围之下时才有效。如果它在另一个函数的作用域内,则必须将该作用域作为附加参数传递并在那里搜索。

    即使在这种情况下,您也无法检查例如在某些闭包结构中定义的函数是否存在。

    【讨论】:

    • 如果代码在任何函数范围内执行,它不会在window下,因为它是用var声明的。
    • @VirtualBlackFox 我只是想为他指出正确的方向,而不是为这里的每个案例提供完整的解决方案。在函数作用域中,他必须将实际作用域作为附加参数传递,runner 可以从该参数开始。当然,即使这样,也不会处理一些关闭案例。
    • @skafandri 当然可以。您的函数被声明为 window['ff']['showAlert']。我只是想指出,标识符中的字符串针对.进行解析。
    • @Sirko 是的,我只是指出了一个细节,我认为无论如何他都应该强制它的代码使用 window 工作。唯一的其他工作解决方案(评估)是丑陋的。
    【解决方案3】:

    您需要拆分多部分函数名称,例如'ff.showAlert'。此外,因为您将 ff 指定为 var,所以它不会是 window 的成员,除非它在任何函数范围之外。它是否来自您的代码示例还不是很清楚。

    不管怎样,下面的函数允许你传入一个基础对象,以防你需要指定window以外的一个,它会拆分多部分函数名:

    function isFnDefined(fnName, baseObj) {
        try {
            var parts = fnName.split('.'),
                ii;
    
            // If no baseObj was provided, default to 'window'.
            baseObj = baseObj || window;
    
            for (ii in parts) {
                baseObj = base[parts[ii]];
            }
    
            return typeof baseObj === 'function';
        }
        catch (e) {
            return false;
        }
    }​
    
    isFnDefined('alert');          // returns true
    isFnDefined('undefinedFunc');  // returns false
    isFnDefined('ff.showAlert');   // returns true, if ff is a member of window 
    isFnDefined('showAlert', ff);  // returns true
    

    【讨论】:

      【解决方案4】:

      【讨论】:

      • 没有。这里不需要 eval。
      【解决方案5】:

      你有一个代表当前范围内的东西的字符串,你想知道它是什么,解决方案是评估字符串。

      var f = undefined;
      try
      {
          f = eval(functions[i]);
      }
      catch(ReferenceError) {}
      console.log(typeof f);
      

      但是为什么你在输入对象中存储字符串而不是函数本身呢?

      此外,如果您可以强制每个字符串都是相对于窗口的引用(当前范围内没有“var”或来自另一个范围的关闭),那么@Sirko 解决方案可能是最好的解决方案。

      【讨论】:

      • 我在页面上有很多按钮,有几个 onclick 动作,我想做的是禁用试图调用未定义函数的按钮..
      猜你喜欢
      • 2012-01-25
      • 2010-09-13
      • 1970-01-01
      • 2010-09-10
      • 1970-01-01
      • 1970-01-01
      • 2014-01-09
      • 1970-01-01
      • 2015-01-18
      相关资源
      最近更新 更多