如何确定函数是否为空

时间:2010-12-03 13:53:28

标签: javascript reflection

我希望能够检查给定的功能是否为空。也就是说,它的身体里没有任何东西,例如:

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

我只是想知道是否有更好的方法?您可以看到以上问题吗?

6 个答案:

答案 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)

你可以尝试的最好的方法,就是要适应最大的可能性(因为这很难实现),就是添加acornesprima也适用于箭头功能)库和处理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;
&#13;
&#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