2010-12-03 74 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()); 
};