2010-12-03 78 views
26

我希望能夠檢查給定函數是否爲空。也就是說,沒有什麼在它的身上,如:如何確定函數是否爲空

function foo() {} 
function iAmEmpty(a) { 
    // yep, empty 
} 

有了一些初步的玩弄,我已經得到了一些東西,我覺得可能是好的,通過使用toString()和一些正則表達式。

function foo(a, b, c) {} 

/^function[^{]+\{\s*\}/m.test(foo.toString()); // true 

function bar(a, b, c) { var d; } 

/^function[^{]+\{\s*\}/m.test(bar.toString()); // false 

我只是想知道是否有更好的方法?上面你可以看到有什麼問題嗎?

+0

有趣的問題...... – 2010-12-03 13:57:07

+1

JS反射的概念讓我笑,但作爲的問題;你已經處理了空白和多行,所以afaik這個效果很好。 – annakata 2010-12-03 13:58:59

+1

不要忘記尋找所有評論的方法體(如果這是你的規範) – Brad 2010-12-03 14:01:44

回答

15

這不可取。沒有標準確定函數的方法應該返回什麼,所以即使你在當前的瀏覽器中使用這個方法,未來的瀏覽器也可能會改變它們的實現並破壞你的代碼。

Kangax寫簡單說一下這個:http://perfectionkills.com/those-tricky-functions/

2

我沒有看到這種情況的使用,但你可以使它更容易被錨定模式字符串的結束

/[^{\s]\s*\}$/.test(String(bar)) 
5

你可以嘗試,以符合最大可能性(因爲這是非常難以實現)的最好的事情,就是(箭頭功能作品太)添加acornesprima庫和處理JavaScript函數。它會標記它爲你解析,所以你可以處理它到你的喜好,檢查裏面是否有實際的零代碼,或者只有變量聲明沒有任何計算和返回,等等......

是非常簡單的實現:

function check(f) { 
 
    console.log(""); 
 
    console.log("Checking", f); 
 
    var syntax = esprima.parse(f); 
 
    if (syntax.body.length != 1) { 
 
    console.log("Weird process"); 
 
    } else { 
 
    function processBody(body) { 
 
     if (!body || body.length == 0) { 
 
     console.log("Body seems empty. YAY!"); 
 
     } else { 
 
     for (var i = 0, command; command = body[i]; i++) { 
 
      if (command.type != "VariableDeclaration") { 
 
      console.log("Body has a", command.type, ", so is not empty."); 
 
      return; 
 
      } 
 
     } 
 
     console.log("Body has only variable declarations, so is empty! (or not, whatever fit your needs)"); 
 
     } 
 
    } 
 
    function process(dec) { 
 
     if (dec.type != "FunctionDeclaration") { 
 
     console.log("Weird declaration"); 
 
     } else { 
 
     console.log("Function", dec.id.name, "has", dec.params.length, "params"); 
 
     processBody(dec.body.body); 
 
     } 
 
    } 
 
    process(syntax.body[0]); 
 
    } 
 
} 
 

 
check("function hasReturn(arg1, arg2) {var a = arg1 + arg2;return a;}"); 
 
check("function hasArgumentsButNoBody(arg1, arg2) {}"); 
 
check("function isCompletelyEmptyWithSpacesAndTabsAndLinefeeds() { \t \t \r\n \r\n }"); 
 
check("function hasOnlyVariables() {var a, b = 2; var c = 1 + b;}");
<script src="https://cdnjs.cloudflare.com/ajax/libs/esprima/2.7.3/esprima.min.js"></script>

這將不會運行的功能,只是解析它們,所以是安全與非安全功能的運行。

7

箭功能...

正如我相信大家都知道,javascript支持arrow functions這是真正的簡潔但遺憾的是不與您的整齊regex工作。

我很快將您的好regex轉換爲它自己的function,它將function作爲輸入,並返回它是否爲空,以便稍後簡化。只是爲了演示如何箭頭功能,可廣泛的應用,我把它放在一個:

isEmpty = f => /^function[^{]+\{\s*\}/m.test(f.toString()) 

現在,我們可以很容易地測試一個空函數:

function eF() {} 

這正如我們期望與isEmpty(eF)回報true

,最後再用一個實際的功能:

function retOne() {return 1;} 

其預期與isEmpty(retOne)回報false一次。

不過,我遇到的問題是帶箭頭的功能,所以要重新初始化空單,我們有原來的更短的語法:

eF =() => {} 

'stringified'版,那是一個很大的不同前:

"() => {}" 

所以當然在這種情況下,呼叫isEmpty(eF)回報false當我們想要true。我不確定是否需要測試是否所有功能(即包括arrow functions)都是空的,但如果你這樣做,你的regex將需要修改...

我不是很擅長自己寫,但已嘗試夫婦和一個進一步的事情,你可能要考慮的是documentationarrow functions尤其是這部分的寬鬆性質:

(param1, param2, …, paramN) => { statements } 
(param1, param2, …, paramN) => expression 
// equivalent to: (param1, param2, …, paramN) => { return expression; } 

// Parentheses are optional when there's only one parameter name: 
(singleParam) => { statements } 
singleParam => { statements } 

這說明大括號{...}如何並不總是必要的。所以這個功能:

retOne =() => 1 

valid並可以使形成新的regex更加困難。我想到的一個解決方法是從f.toString()刪除所有大括號使用:

str.replace(/[{}]/g, '')

然後從那裏使用regex test

希望這是有幫助的考慮,如果你想要arrow functions也能夠被測試。

1

這很簡單,只需檢查包含的功能,然後檢查包含是否爲空。
檢查這個Plunker
這裏有完整的工作代碼:

function foo(a, b, c) {} 

function bar(a, b, c) { 
    var d; 
} 

function isEmpty(value) { 
    return (value == null || value.length === 0); 
} 

function check(test) { 
    var entire = test.toString(); 
    var body = entire.slice(entire.indexOf("{") + 1, entire.lastIndexOf("}")); 
    return body; 

} 
console.log(isEmpty(check(foo)), isEmpty(check(bar))); //return true false 
2
Function.prototype.hasBody = function() { 
    return !/{\s*}$/.test(this.toString()); 
};