Подтвердить что ты не робот

Javascript get function body

У меня есть функция, например.

var test = function () {alert(1);}

Как я могу получить тело этой функции?

Я предполагаю, что единственный способ - проанализировать результат метода test.toString(), но есть ли другой способ? Если синтаксический анализ является единственным способом, каким будет регулярное выражение, чтобы добраться до тела? (помощь с регулярным выражением крайне необходима, потому что я не знаком с ними)

4b9b3361

Ответ 1

IF (!!!) вы можете получить toString(), тогда вы можете просто взять подстроку от первого indexOf("{") до lastIndexOf("}"). Итак, что-то вроде этого "работает" (как видно на ideone.com):

var test = function () {alert(1);}

var entire = test.toString(); // this part may fail!
var body = entire.substring(entire.indexOf("{") + 1, entire.lastIndexOf("}"));

print(body); // "alert(1);"

Ответ 2

Обновление 2015

После пересмотра состояния декомпиляции функции он может сказать, что он в целом безопасен в определенных <сильных > хорошо рассмотренных случаях использования и средах (например: Node.js-работники с определенными пользователем функциями).

Он должен быть помещен в то же самое ведро, что и eval, что является мощным инструментом, который имеет свое место, но его следует использовать только в редких случаях. Подумайте дважды, это мой единственный совет.

Выводы Новые исследования Kangax:

  • Он по-прежнему не стандартный
  • Пользовательские функции, как правило, выглядят разумно
  • Есть нечетные двигатели (особенно когда речь идет о исходном коде размещение, пробелы, комментарии, мертвый код)
  • Там могут быть будущие двигатели с нечетным двигателем (особенно мобильные или необычные устройства с консервативной памятью/энергопотреблением)
  • Связанные функции не показывают исходный источник (но сохраняют идентификатор... иногда)
  • Вы можете запустить нестандартные расширения (например, выражение Mozilla закрытие)
  • ES6 приближается, и теперь функции могут выглядеть совсем иначе, чем они использовали
  • Minifiers/препроцессоры не являются вашим другом.

"декомпиляция функции" - процесс получения строковое представление объекта Function.

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

@kangax на comp.lang.javascript

Ответ 3

Простейший пример использования

Если вы просто хотите выполнить тело функции (например, с помощью eval или с помощью API Worker), вы можете просто добавить код, чтобы обойти все ловушки извлечения тела функции (что, как упоминалось другими, является плохой идеей вообще):

'(' + myFunction + ')()';

Я использую этот трюк в этот Worker -связанный JSFiddle.

Полная сериализация функций с точной stacktrace

Я также написал более полную библиотеку, которая может:

  • Сериализовать любую функцию в строке
  • Уметь отправлять это строковое представление в другом месте, выполнять его с любыми настраиваемыми аргументами и иметь возможность воспроизводить исходную стекю

Посмотрите мой код CodeBuilder здесь.

Обратите внимание, что большая часть кода заботится о том, чтобы мы получили точную стеклу, где бы мы не выполнили сериализованную функцию в более поздний момент времени.

Эта скрипта демонстрирует упрощенную версию этой логики:

  • Используйте JSON.stringify для правильной сериализации функции (что очень удобно, когда, например, мы хотим сделать ее частью пакета данных большего размера).
  • Затем мы завершим его в один eval, чтобы избежать escape-строки "JSON-ish" (JSON не разрешает функции + код, поэтому мы должны использовать eval), а затем в другом eval чтобы вернуть желаемый объект.
  • Мы также используем //# sourceMappingURL (или старую версию //@ sourceMappingURL), чтобы показать правильное имя функции в стеке.
  • Вы обнаружите, что Stacktrace выглядит нормально, но он не дает вам правильной информации о строках и столбцах относительно файла, в котором мы определили сериализованные функции, поэтому мой CodeBuilder использует stacktracejs, чтобы исправить это.

Я использую материал CodeBuilder в моей (теперь слегка устаревшей) RPC-библиотеке, где вы можете найти несколько примеров того, как она используется:

Ответ 4

расширение @polygenelubricants answer:

, используя: .toString()

испытуемый:

var y = /* olo{lo} */
    /* {alala} */function/* {ff} */ x/*{s}ls{
}ls*/(/*{*{*/)/* {ha-ha-ha} */
/*

it a function

*/
{
  return 'x';
// }
}
/*
*/

indexOf и lastIndexOf:

function getFunctionBody(fn) {
    function removeCommentsFromSource(str) {
        return str.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '$1');
    }
    var s = removeCommentsFromSource( fn.toString() );
    return s.substring(s.indexOf('{')+1, s.lastIndexOf('}'));
};

getFunctionBody(y);
/*
"
  return 'x' 
"
*/

используется: комментарии rm из источника js

Ответ 5

var fn1 = function() {};
var fn2 = function() { alert("lol!"); };

Function.prototype.empty = function() {
var x = this.toString().match(/\s*function\s*\w*\s*\(.*?\)\s*{\s*}\s*;?\s*/);
return x != null;
};

alert(fn1.empty()); // true
alert(fn2.empty()); // false

"   Solução proposta pelo Paulo Torres no grupo A.P.D.A. нет facebook.

Ответ 6

Этот код обеспечивает тело при использовании функций стрелок ES6, таких как var testFn=(q)=>q+1;

function getFunctionBody(test){  
    var entire = test.toString(); // note: not safe-guarded; this part may fail like this!
    return entire.substring((entire.indexOf("{")+1)||(entire.indexOf("=>")+2),  entire.lastIndexOf("}")!==-1?entire.lastIndexOf("}"):entire.length);
}

//testing/showcase code
var tests = [
    function () {alert(1);},
    ()=>{return 1;},
    q=>q+1
];

for (var i=0;i<tests.length;i++){
    console.log(tests[i],getFunctionBody(tests[i]));
}

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

Ответ 7

Вы можете попробовать эту функцию:

function extractFunctionBody(fn) {
    var reg = /function \((.*)\)[ ]?{(.*)}$/g;
    var match = reg.exec(fn.toString().replace(/\n/g, ";"));
    if (match){
        return match[2];
    } else {
        return "";
    }
}

Ответ 8

Попробуйте следующее:

/\{(\s*?.*?)*?\}/g.exec(test.toString())[0]

test.toString() будет содержать все ваше объявление.

/{(\ s *?.?)?}/g будет соответствовать всем между фигурными скобками