7

I have implemented some module, which simplified code is shown below:

(function() {
    var context = {...}; // an object which serves as the context for the expression being evaluated
    with (context) {
        var x = eval(expression);
        ...
    }
}());

Just to clarify, I have full control over the expression and over dynamically created context object. Expression is always safe and provided from trusted source. All members (fields and functions) appearing in the expression always exist in the context object e.g.

var context = {
    Concat: function(strA, strB) { return [strA, strB].join(''); },
    Name: 'ABC',
    Surname: 'DEF'
}

with (context) {
    var x = eval("Concat(Name, Surname) == 'XYZ'"); // evaluates to false
    ...
}

Now, I'd like to insert the 'use strict'; pragma as the first line of the module (let's assume for some reasons I want this for entire module, I don't want to apply strictness to narrowed set of function scopes and mix strict code with sloppy one within this module).

Because of that I need to change my code to pass strict mode requirements, because, as noted in ECMAScript 5.1 specification, with statements are not allowed in strict mode.

I've hacked this by doing following modification to extort the compatibility:

(function() {
    'use strict';

    function ctxEval(exp, ctx) { // evaluates expression in the scope of context object
        return (new Function('expression', 'context', 'with(context){return eval(expression)}'))(exp, ctx);
    }
    var context = {...};
    var x = ctxEval(expression, context);
    ...
}());

(additional pragma intentionally not put to Function constructor, this kind of strict and sloppy code mix I can accept)

Are there any drawbacks of this approach in terms of performance or safety when compared to first version? Can you provide any better solution which satisfies strict mode preserving the same set of functionality?

jwaliszko
  • 16,942
  • 22
  • 92
  • 158
  • What's the reason for keeping data in an object — and then using `with` to allow access to it via variables — instead of just using variables in the first place? – kangax Mar 17 '15 at 17:42
  • My suggestion is to ditch `with` and never look back :) But if you insist, of course you can just move method outside of scope of "use strict" directive: `function evalInContext(context, expression) { with(context) { return eval(expression) } } (function(){ "use strict"; var context = { ... } evalInContext(...) })()` (excuse the brevity) – kangax Mar 17 '15 at 17:48
  • @kangax: Thanks for suggestion. I don't really insist on that solution I've posted. It is just [an easiest attempt of solving an issue](https://github.com/JaroslawWaliszko/ExpressiveAnnotations/issues/51]), which has been posted by one of the users of the library I've written. One drawback I see in my code is probably performance related. Mainly (I'm not sure, but I think that) JavaScript interpreter is invoked two times now (instead of only one as before) - not only for calculating `eval` method as previously, but additionally for evaluating function body given to function constructor. – jwaliszko Mar 17 '15 at 23:01
  • Wel... `with` usually kills all the optimizations (due to scope chain injection), so if performance is a concern, it's even more advisable to avoid it – kangax Mar 18 '15 at 13:36
  • Really nice hack to circumvent "use strict" in edge cases. Exactly what I needed... – adroste Dec 07 '20 at 17:14

0 Answers0