15

I want to know how to convert a function's body into a string?

function A(){
  alert(1);
}

output = eval(A).toString() // this will come with  function A(){  ~ }

//output of output -> function A(){ alert(1); }

//How can I make output into alert(1); only???
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Micah
  • 4,254
  • 8
  • 30
  • 38

5 Answers5

35

If you're going to do something ugly, do it with regex:

A.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1];
nrabinowitz
  • 55,314
  • 10
  • 149
  • 165
  • thank you very much!!! can I also ask do you have any reference sites are giving good teaching about how to use regex?? – Micah Feb 14 '13 at 23:47
  • 8
    I don't agree with what the OP's doing, but I do agree that: 'if you're going to do something ugly (you might as well) do it with regex.' =D – David Thomas Feb 14 '13 at 23:48
  • 1
    yes, I understand this is ugly.. but still depends on what are you building....the function in js is value only, it means string.. – Micah Feb 14 '13 at 23:49
  • 3
    "If you're going to do something ugly, do it with regex:" Quote of the Week! – Duncan Sep 24 '13 at 15:42
  • 1
    This does not work for functions defined like `() => {}`. Run this code for an example `(() => {console.log(1);}).toString().match(/function[^{]+\{([\s\S]*)\}$/)[1];` – MattCochrane Nov 19 '17 at 10:22
  • Funny enough, if you do `function a(b = {}) { // c }` it will match `}) { // c`. Therefor, this post is not really useful. – Mr.DeleteMyMessages Mar 11 '19 at 09:42
  • @Mr.DeleteMyMessages: Please check the date, I wrote this before this syntax was valid. You may need alternate regex to match default arg values, destructuring, arrow funcs, and other new features. But if you’re doing that you may be using a transpiler, in which case this approach is probably a Bad Idea to begin with (because your transpiled code may have different source from what you expect). – nrabinowitz Mar 11 '19 at 14:04
8

Don't use a regexp.

const getBody = (string) => string.substring(
  string.indexOf("{") + 1,
  string.lastIndexOf("}")
)

const f = () => { return 'yo' }
const g = function (some, params) { return 'hi' }
const h = () => "boom"

console.log(getBody(f.toString()))
console.log(getBody(g.toString()))
console.log(getBody(h.toString())) // fail !
pushkin_
  • 5
  • 1
  • 2
Clemens
  • 1,302
  • 2
  • 15
  • 12
  • 1
    won't work if my function bears an argument with such default value: `function fn(a = {}) { return "hello"; }` – ips Mar 26 '21 at 08:26
2

You could just stringify the function and extract the body by removing everything else:

A.toString().replace(/^function\s*\S+\s*\([^)]*\)\s*\{|\}$/g, "");

However, there is no good reason to do that and toString actually doesn't work in all environments.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Or more concisely: f.toString().replace(/(^.*?\{|\}$)/g, "") – rich remer Dec 07 '13 at 08:34
  • This does not work for functions defined like `() => {}`. Run this code for an example `(() => {console.log(1);}).toString().replace(/^function\s*\S+\s*\([^)]*\)\s*\{|\}$/g, "");` – MattCochrane Nov 19 '17 at 10:20
  • 2
    @MattClimbs Of course it doesn't, the answer is from 2013 :-) It also doesn't work on concise methods, generators, async functions… If you want to recognise an ES6 function with default parameter initialisers, you need a proper parser - regex is not enough. – Bergi Nov 19 '17 at 12:57
0

Currently, developers are using arrow functions with the new releases of Ecmascript.

Hence, I would like to share the answer here which is the answer of Frank

    function getArrowFunctionBody(f) {
      const matches = f.toString().match(/^(?:\s*\(?(?:\s*\w*\s*,?\s*)*\)?\s*?=>\s*){?([\s\S]*)}?$/);
      if (!matches) {
        return null;
      }
      
      const firstPass = matches[1];
      
      // Needed because the RegExp doesn't handle the last '}'.
      const secondPass =
        (firstPass.match(/{/g) || []).length === (firstPass.match(/}/g) || []).length - 1 ?
          firstPass.slice(0, firstPass.lastIndexOf('}')) :
          firstPass
      
      return secondPass;
    }
    
    const K = (x) => (y) => x;
    const I = (x) => (x);
    const V = (x) => (y) => (z) => z(x)(y);
    const f = (a, b) => {
      const c = a + b;
      return c;
    };
    const empty = () => { return undefined; };
    console.log(getArrowFunctionBody(K));
    console.log(getArrowFunctionBody(I));
    console.log(getArrowFunctionBody(V));
    console.log(getArrowFunctionBody(f));
    console.log(getArrowFunctionBody(empty));

Original question here

Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254
  • In my case I used: `^(?:\s*function)?.*\(.*\)(?:\s*=>)?\s*\{[ \t]*\r?\n?([^]*)(?=\})` which doesn't need special cases for `}` as it uses lookahead group. – AgainPsychoX Feb 13 '22 at 04:46
0

This coud be what youre looking for

const toString = (func) => `(${func.toString()})()`
    
console.log(toString(() => {
    console.log("Hello world")
}))

This will execute the function.

PowerKuu
  • 63
  • 7