© 2019 Meouzer Consortium

JavaScript: Copying Functions with Evaluators Part 2

Draft 1: By draft 20 we will get it right!

Meouzer the Snarky Cat Programming Cat Making Eval Great Again! meouzer@gmail.com
loading
This article shows a better way to copy functions! So you read the previous article? Oops!
Meouzer

The previous article is a good introduction to context evaluation factories and evaluators. It was all so simple, but now it gets more complicated. Good luck! We at the consortium hope you can now figure out the code below.

Full code is at evaluators.js, which has no dependencies.

Introduction

We show the most powerful way to copy functions. Not only vars but constants and lets can be placed into the evaluator's context, which are seen by all the copied functions. This comes close to the way that functions and getter/setters are copied when we get to copying class instances.

Infrastrucure for Copying Functions

The context evaluation factory getEvaluator()
function writeVars(contextObject) { var vars = ""; if(contextObject != null && typeof contextObject == "object") { const regVar = /^(var |let |const )?([a-zA-z_$][a-zA-z_$0-9]*)$/; for(let i = 0, keys = Object.keys(contextObject), length = keys.length; i < length; i++) { var a = regVar.exec(keys[i]); vars += (a[1]?a[1]:"var ") + a[2] + " = arguments[0]['" + keys[i] + "'];"; } } return vars; } function getEvaluator() { return eval("(function()\ {" + writeVars(arguments[0]) + "return function(){return eval('('+arguments[0]+')');}\ });")(arguments[0]); } const Evaluator = '(' + getEvaluator + ')';

Example

A Local Context Evaluation Factory and Evaluator
function Test() { // This Z would be in the evalautor's context but it is overriden // in a nested scope. var Z = 100; (function(){ // Here the scope is local, not global. var Z = 0; // used since Z is local // local but not used since b is overriden by the context object. var b = 9; // In evaluator context, b is a const and c is a var. // eval(Evaluator) is the local context evaluation factory. const evaluator = eval(Evaluator)({"const b":2, c:3}); // sum is the copy a function, and lives in the evaluator's context. const sum = evaluator(function(a){return a + b + c + Z}); // const b = 2, var c = 3 and Z = 0 are in the evaluator's context. console.log(sum(1)); // 1 + 2 + 3 + 0 = 6 // setB is the copy a function, and lives in the evaluator's context. const setB = evaluator(function(value){b = value}); try { // Attempt to change const b in evaluator's context to 100. setB(100); } catch(e) { console.log(e.message); // invalid assignment to const 'b' } })(); }