开发者

javascript get function body

I have a function e.g.

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

How can I get the body of this function?

I assume that the only way is to parse the result of test.toString() method, but开发者_StackOverflow is there any other way? If parsing is the only way, what will be the regex to get to body? (help with the regex is extremly needed, because I am not familiar with them)


IF(!!!) you can get the toString(), then you can simply take the substring from the first indexOf("{") to the lastIndexOf("}"). So, something like this "works" (as seen on 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);"


2015 update

Upon revisiting the state of function decompilation, it can said that it's generally safe in certain well-considered use cases and enviroments (e.g: Node.js workers with user defined functions).

It should be put in the same bucket as eval, which is a powerful tool that has its place, but should only be used on rare occasions. Think twice, that's my only advice.

The conclusions from Kangax's new research:

  • It's still not standard
  • User-defined functions are generally looking sane
  • There are oddball engines (especially when it comes to source code placement, whitespaces, comments, dead code)
  • There might be future oddball engines (particularly mobile or unusual devices with conservative memory/power consumption)
  • Bound functions don't show their original source (but do preserve identifier... sometimes)
  • You could run into non-standard extensions (like Mozilla's expression closures)
  • ES6 is coming, and functions can now look very different than they used to
  • Minifiers/preprocessors are not your friend

"function decompilation" — a process of getting string representation of a Function object.

Function decompilation is generally recommended against, as it is a non-standard part of the language, and as a result, leads to code being non-interoperable and potentially error-prone.

@kangax on comp.lang.javascript


Simplest Use-Case

If you just want to execute the body of the function (e.g. with eval or using the Worker API), you can simply add some code to circumvent all the pitfalls of extracting the body of the function (which, as mentioned by others, is a bad idea in general):

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

I am using this trick in this Worker-related JSFiddle.

Complete Function Serialization With Accurate Stacktrace

I also wrote a more complete library that can:

  1. Serialize any kind of function to string
  2. Be able to send that string representation anywhere else, execute it with any custom arguments, and be able to reproduce the original stacktrace

Check out my CodeBuilder code here.

Note that much of the code takes care of making sure that we get an accurate stacktrace, wherever we execute the serialized function at a later point in time.

This fiddle demonstrates a simplified version of that logic:

  1. Use JSON.stringify to properly serialize the function (that comes in handy when, e.g., we want to make it part of a bigger serialization "data package").
  2. We then wrap it in one eval to un-escape the "JSON-ish"-escaped string (JSON does not allow functions + code, so we must use eval), and then in another eval to get back the object we wanted.
  3. We also use //# sourceMappingURL (or the old version //@ sourceMappingURL) to show the right function name in the stacktrace.
  4. You will find that the Stacktrace looks Ok, but it does not give you the correct row and column information relative to the file that we defined the serialized functions in, which is why my Codebuilder makes use of stacktracejs to fix that.

I use the CodeBuilder stuff in my (now slightly dated) RPC library where you can find some examples of how it is used:

  1. serializeInlineFunction example
  2. serializeFunction example
  3. buildFunctionCall example


extending @polygenelubricants' answer:

using: .toString()

Testee:

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

it's a function

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

By indexOf and 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' 
"
*/

used: rm comments from js source


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. no facebook.


This code provides the body when using ES6 arrow functions like 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]));
}

I originally submitted this code as an edit to polygenelubricants accepted answer, but it was rejected as the changes were considered to be too drastic.


you can try this functiion:

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


Try this:

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

test.toString() will hold your entire declaration.

/{(\s*?.?)?}/g will match everything between your braces

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜