Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving outer-scope references in a javascript function for serialization

var foo = (function(){
  var x = "bar";
  return function(){
    console.log(x);
  };
})();

console.log(foo.toString()); // function() {console.log(x);}
(foo)(); // 'bar'
eval('(' + foo.toString()+')()')); // error: x is undefined

Is there a technique for resolving (modifying) a function, so references from outer scope become local references, like:

function() {console.log(x);}

becomes:

function() {console.log("bar");}

The function can now be stringified and transported across a network and executed in another runtime.

Maybe one could parse the function to an Abstract Syntax Tree and then modify it? The reference will always be out of scope (not available), right?

The objective:

I am serializing a filter function from a node runtime to a postgresql plv8 runtime. Right now the filter function has interface: dbClient.filter((row, age) => row.age > age), ageFromOuterScope).then(matches => ...)

I want interface dbClient.filter((row) => row.age > age)).then(matches => ...), where age is a reference from outer scope.

Update:

I can only imagine one solution. Analyze the function, detect references to variables outside the function, and then rewrite the original function:

function(row) {
   return row.age > age
}

To:

function(row, age) {
  return row.age > age
}

Detected variables should also be added to a string that represent an array, like:

var arrayString = '[age]'

And then eval the string:

var functionArgs = eval(arrayString)

And finally:

dbClient.filter(modifiedFunction, ...functionArgs).then(matches => ...)
like image 306
Jacob Avatar asked Oct 11 '15 04:10

Jacob


1 Answers

To expose the private variable outside the scope you need another function within the scope that rewrites the method description returned by toString. Then you use that function instead of toString to retrieve the method description.

var foo = (function(){
  var x = "bar";

  var f = function(){
    console.log(x);
  };

  f.decl = function() {
      return f.toString().replace("(x)", "(\""+x+"\")");
  }

  return f;

})();

console.log(foo.decl()); // function() {console.log("bar");}

eval("("+foo.decl()+")()"); // bar
like image 189
Fluster Avatar answered Sep 23 '22 01:09

Fluster