2012-05-04 51 views
3

我要检查,如果一个函数的定义(我不在乎怎么样,我的意思是它是可调用)
如何确定是否定义了JavaScript函数?

示例代码:

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
有没有办法以编程方式检查函数是否存在?

+0

可能重复javascript函数存在(http://stackoverflow.com/questions/798340/testing-if-javascript-function-exists) –

+0

不,没有,在他**知道的情况下**函数名,在我的情况我不要.. – skafandri

回答

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 
+0

太好了!这完美的作品! [演示](http://jsfiddle.net/GrJbC/6/) – skafandri

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。如果它在另一个函数的作用域内,则必须将该作用域作为附加参数传递并在那里搜索。

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

+0

如果代码在任何函数范围内执行,它将不会在窗口下,因为它是用var声明的。 –

+0

事实上,窗口[“ff.showAlert”]返回undefined .. http://jsfiddle.net/GrJbC/5/ – skafandri

+0

@VirtualBlackFox我只是想点他在正确的方向,并不能提供任何情况下一个完全成熟的解决方案这里。在一个函数范围内,他必须将实际范围作为附加参数传递,这个'runner'可以从其开始。当然,即使这样,一些关闭案件也没有得到照顾。 – Sirko

-2

您有代表在当前范围内的东西的字符串,你想知道它是什么,解决的办法是给eval的字符串。

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

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

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

+0

我在网页上的按钮,有几个的onclick行动,我想要做的是禁用按钮,尝试调用未定义功能.. – skafandri

0

您需要拆分像'ff.showAlert'多部分函数名称。此外,因为您指定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 
[测试如果
相关问题