我希望能够检查给定的功能是否为空。也就是说,它的身体里没有任何东西,例如:
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 :(得分:14)
这是不可取的。没有标准确定函数的toString()
方法应该返回什么,所以即使你在当前的浏览器中使用它,未来的浏览器也可以合理地改变它们的实现并破坏你的代码。
Kangax简要地写了这个:http://perfectionkills.com/those-tricky-functions/
答案 1 :(得分:6)
我确信您知道,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
将需要修改...
我自己写的不是很好,但是你想要考虑的另外一件事是arrow functions
的宽容本质,尤其是documentation的这部分: / p>
(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
也能够进行测试,希望这有助于考虑。
答案 2 :(得分:4)
你可以尝试的最好的方法,就是要适应最大的可能性(因为这很难实现),就是添加acorn或esprima(也适用于箭头功能)库和处理JavaScript函数。它会将它标记为你解析,所以你可以根据自己的喜好处理它,检查里面是否真的没有代码,或者只有变量声明,没有任何计算或返回等等...... / p>
实施非常简单:
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>
&#13;
这不会运行函数,只需解析它们,因此使用非安全函数运行是安全的。
答案 3 :(得分:1)
我没有看到它的用途,但你可以通过将模式锚定到字符串的 end 来简化它。
/[^{\s]\s*\}$/.test(String(bar))
答案 4 :(得分:1)
Function.prototype.hasBody = function() {
return !/{\s*}$/.test(this.toString());
};
答案 5 :(得分:0)
只需检查函数是否包含然后检查包含是否为空
检查此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