Free email newsletter: “ES.next News

2012-04-04

Handing variables to eval

Problem: You have an object that assigns values to names and want to use those names in an expression that is to be evaluated by eval. The classic solution is to use the with statement. But that statement is deprecated [1], starting with ECMAScript 5 strict mode [2]. This blog post describes an alternative implementation technique.

Let’s assume we want to implement a function

    evalExpr(expr, vars)
That function evaluates expr, the object in vars provides the values for variables. Example:
    > evalExpr("x + y", { x: 5, y: 3 })
    8
The classic approach is:
    function evalExpr(expr, vars) {
        with (vars) {
            return eval(expr);
        }
    }
But that approach uses the controversial with statement. A different approach comprises the following steps:
  • Wrap a function expression (not a function declaration!) around expr whose parameters are the variables listed in vars.
  • Evaluate the function expression.
  • Call the resulting function with the property values of vars, in the same order as the parameters.
You should normally steer away from using Function to produce functions, but here it is useful, because it wraps the parameters and the body for you.
    function evalExpr(expr, vars) {
        var keys = Object.keys(vars);
        // Function(param1, ..., paramn, body)
        var exprFunc = Function.apply(null, keys.concat(["return "+expr]));
        var args = keys.map(function (key) { return vars[key] });
        return exprFunc.apply(null, args);
    }
The above code uses ECMAScript 5 functionality (Object.keys(), Array.prototype.map()), but you can add that functionality to older browsers via a shim [3].

Note that the usual security concerns about eval apply here, too: You have to make sure that all ingredients come from trusted sources. But there are legitimate uses for this technique, e.g. for templating.

References:

  1. JavaScript’s with statement and why it’s deprecated
  2. JavaScript’s strict mode: a summary
  3. es5-shim: use ECMAScript 5 in older browsers

No comments: