Javascript get function body
У меня есть функция, например.
var test = function () {alert(1);}
Как я могу получить тело этой функции?
Я предполагаю, что единственный способ - проанализировать результат метода test.toString(), но есть ли другой способ? Если синтаксический анализ является единственным способом, каким будет регулярное выражение, чтобы добраться до тела? (помощь с регулярным выражением крайне необходима, потому что я не знаком с ними)
Ответы
Ответ 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 будет соответствовать всем между фигурными скобками