3

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

示例代码:

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

现场演示
有没有办法以编程方式检查函数是否存在?

4

5 回答 5

6

编码:

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
于 2012-05-04T13:08:27.720 回答
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 在评论中指出的那样:上述解决方案仅在函数在window-scope 之下声明时才有效。如果它在另一个函数的范围内,则必须将该范围作为附加参数传递并在那里搜索。

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

于 2012-05-04T13:01:14.807 回答
0

您需要拆分多部分函数名称,例如'ff.showAlert'. 此外,由于您指定为 var,除非它超出任何函数范围,否则它ff不会成为成员。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
于 2012-05-04T13:14:11.107 回答
-1

您需要使用 eval():http ://www.w3schools.com/jsref/jsref_eval.asp

于 2012-05-04T13:02:01.910 回答
-2

您有一个代表当前范围内某些内容的字符串,并且您想知道它是什么,解决方案是评估该字符串。

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

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

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

于 2012-05-04T13:03:10.860 回答