Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I "recursively" stringify a javascript function which calls other scoped functions?

Because javascript functions are not serializable, in order to pass them into new contexts sometimes (albeit rarely) it can be useful to stringify them then re-evaluate them later like:

const foo = () => { // do something }
const fooText = foo.toString()

// later... in new context & scope
const fooFunc = new Function(' return (' + fooText + ').apply(null, arguments)')
fooFunc() // works!

However, if foo references another function bar, the scope is not stringified, so if bar is not defined in the new context, the evaluated foo function will throw an error when called.

I'm wondering if there is a way to stringify a function recursively?

That is, not only stringifying the parent function, but also stringifying the contents of the child functions called from the parent.

For Example:

let bar = () => { alert(1) }
let foo = () => { bar() }

// what toString does
let fooString = foo.toString()
console.log(fooString) // "() => { bar() }"

// what we want
let recursiveFooString = foo.recursiveToString()
console.log(recursiveFooString) // "() => { alert(1) }"

Let me know if you have any ideas on how to accomplish something like a "recursiveToString"

like image 688
Zachary Denham Avatar asked Nov 01 '19 07:11

Zachary Denham


1 Answers

The only good way to do this is to start from a parent scope that encloses all functions foo eventually references. For example, with your foo and bar, if you want to pass foo into another context such that bar is callable as well, pass a function that declares both foo and bar, and returns foo. For example:

const makeFoo = () => {
  let bar = () => { alert(1) }
  let foo = () => { bar() }
  return foo;
};
const makeFooStr = makeFoo.toString();

// ...

const makeFooFunc = new Function(' return (' + makeFooStr + ').apply(null, arguments)');
const foo = makeFooFunc();
foo();

Implementing this sort of thing well does require premeditated design like above (unfortunately). You can't really include all ancestor LexicalEnvironments (the internal map of variable names to values in a given scope) when stringifying.

like image 177
CertainPerformance Avatar answered Oct 20 '22 05:10

CertainPerformance