Как определить, является ли функция пустой - PullRequest
25 голосов
/ 03 декабря 2010

Я хочу иметь возможность проверить, является ли данная функция пустой или нет.То есть в его теле нет ничего, например:

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 ]

14 голосов
/ 03 декабря 2010

Это не рекомендуется. Не существует стандарта, точно определяющего, что именно должен возвращать метод toString() функции, поэтому даже если вы работаете в текущих браузерах, будущие браузеры могут обоснованно изменить свою реализацию и нарушить код.

Кангакс кратко написал об этом: http://perfectionkills.com/those-tricky-functions/

6 голосов
/ 03 августа 2017

Функции стрелок ...

Как я уверен, вы знаете, javascript поддерживает функции стрелок , которые действительно лаконичны, но, к сожалению, не работают с вашими аккуратными 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, особенно этой части документации :

(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 также можно было тестировать.

4 голосов
/ 03 августа 2017

Лучшее, что вы можете попробовать, чтобы соответствовать максимальным возможностям (поскольку это довольно сложно достичь), это добавить желудь или esprima ( работает со стрелкой Функции тоже ) библиотеки и обрабатывают функцию 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>

Это не будет запускать функции, просто проанализировать их, поэтому безопасно работать с небезопасными функциями.

1 голос
/ 10 августа 2017
Function.prototype.hasBody = function() {
    return !/{\s*}$/.test(this.toString());
};
1 голос
/ 03 декабря 2010

Я не вижу смысла в этом, но вы могли бы упростить его, привязав шаблон к end строки.

  /[^{\s]\s*\}$/.test(String(bar))
0 голосов
/ 09 августа 2017

Это просто, просто проверьте содержание функции, а затем проверьте содержание, если оно пустое или нет.
проверить это Плункер
вот полный рабочий код:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...