JavaScript получить тело функции - PullRequest
25 голосов
/ 05 июля 2010

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

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

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

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

Ответы [ 8 ]

44 голосов
/ 05 июля 2010

ЕСЛИ (!!!) вы можете получить 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);"
10 голосов
/ 05 июля 2010

2015 обновление

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

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

Выводы из нового исследования Кангакса :

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

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

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

@ kangax on comp.lang.javascript

6 голосов
/ 06 апреля 2014

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

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

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

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

Полная сериализация функций с помощью точного отслеживания стека

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

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

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

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

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

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

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

  1. serializeInlineFunction пример
  2. serializeFunction пример
  3. buildFunctionCall пример
3 голосов
/ 10 августа 2014

расширение @polygenelubricants ' ответ :

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

Тестируемый1013 *

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

it's 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' 
"
*/

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

0 голосов
/ 10 мая 2019

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

function extractFunctionBody(fn) {
    var reg = /function \((.*)\)[ ]?{(.*)}$/g;
    var match = reg.exec(fn.toString().replace(/\n/g, ";"));
    if (match){
        return match[2];
    } else {
        return "";
    }
}
0 голосов
/ 05 сентября 2017

Этот код предоставляет тело при использовании функций со стрелками 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]));
}

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

0 голосов
/ 29 ноября 2013
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

Решение о предложении Paulo Torres no grupo нет фейсбука.

0 голосов
/ 05 июля 2010

Попробуйте это:

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

test.toString () будет содержать всю вашу декларацию.

/ {(\ s *?. ?) ?} / G будет соответствовать всему между скобками

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...