2012-05-04 76 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 
[測試如果
相關問題