calling eval() in particular context

前端 未结 14 1035
说谎
说谎 2020-11-27 17:05

I have following javaScript \"class\":

A = (function() {
   a = function() { eval(...) };
   A.prototype.b = function(arg1, arg2) { /* do something... */};
}         


        
相关标签:
14条回答
  • var evalWithinContext = function(context, code)
    {
        (function(code) { eval(code); }).apply(context, [code]);
    };
    evalWithinContext(anyContext, anyString);
    
    0 讨论(0)
  • 2020-11-27 17:58

    Actually you can accomplish this with an abstraction via a function:

    var context = { a: 1, b: 2, c: 3 };
    
    function example() {
        console.log(this);
    }
    
    function evalInContext() {
        console.log(this);        //# .logs `{ a: 1, b: 2, c: 3 }`
        eval("example()");        //# .logs `{ a: 1, b: 2, c: 3 }` inside example()
    }
    
    evalInContext.call(context);
    

    So you call the function with the context you want and run eval inside that function.

    Oddly, this seems to be working for me locally but not on Plunkr!?

    For a succinct (and arguably succulent ;) version you can copy verbatim into your code, use this:

    function evalInContext(js, context) {
        //# Return the results of the in-line anonymous function we .call with the passed context
        return function() { return eval(js); }.call(context);
    }
    

    EDIT: Don't confuse this and "scope".

    //# Throws an error as `this` is missing
    console.log(evalInContext('x==3', { x : 3}))
    
    //# Works as `this` is prefixed
    console.log(evalInContext('this.x==3', { x : 3})) 
    

    While one could do this:

    function evalInScope(js, contextAsScope) {
        //# Return the results of the in-line anonymous function we .call with the passed context
        return function() { with(this) { return eval(js); }; }.call(contextAsScope);
    }
    

    to bridge the gap, it's not what OP's question asked and it uses with, and as MDN says:

    Use of the with statement is not recommended, as it may be the source of confusing bugs and compatibility issues. See the "Ambiguity Contra" paragraph in the "Description" section below for details.

    But it does work and isn't too "bad" (whatever that means), so long as one is aware of the oddnessess that can arise from such a call.

    0 讨论(0)
  • 2020-11-27 18:02

    Folks, I think that I have the definitive answer. It works on both JavaScript (Browsers) and NodeJs.

    function evalInContext(Context,toEval){
      return eval(`(function Main(){${toEval}})`).call(Context);
    }
    
    var context = {a:42,b:82,c:103};
    var toEval = "return this";
    
    console.log(evalInContext(context,toEval));//{"a": 42, "b": 82, "c": 103}

    Tested on Node v12.16.1, Node v14.7.0, Firefox v79.0 and Google Chrome v84.0.4147.105

    0 讨论(0)
  • 2020-11-27 18:08

    Edit

    Even though, eval.call and eval.apply do not force the context to be passed in correctly, you can use a closure to force eval to execute in the required context as mentioned in the answers of @Campbeln and @user3751385

    My original answer

    This is not possible. Eval is called only in the local context(is used directly) or in the global context (even if you use eval.call).

    For example, a = {}; eval.call(a, "console.log(this);"); //prints out window, not a

    For more information, look at this great article here

    0 讨论(0)
  • 2020-11-27 18:09

    definitely not the right answer, and please do not use with statement, unless you know what you're doing, but for the curious, you can do this

    Example

        var a = {b: "foo"};
        with(a) {
            // prints "foo"
            console.log(eval("b"));  
            
            // however, "this.b" prints undefined
            console.log(eval("this.b"));
        
            // because "this" is still the window for eval
            // console.log(eval("this")); // prints window
    
    // if you want to fix, you need to wrap with a function, as the main answer pointed out
            (function(){
    	         console.log(eval("this.b")); // prints foo
            }).call(a);     
        }
        
        // so if you want to support both    
        with (a) {
        	(function (){
            console.log("--fix--");
          	console.log(eval("b")); // foo
            console.log(eval("this.b")); // foo
          }).call(a);
        }

    with is the failed attempt to create block scopes within functions, kind of what the ES6's let is designed to do. (but not exactly, open and read the resource links)

    0 讨论(0)
  • 2020-11-27 18:09

    This solved my problem.

     function evalInContext(js, context) {
        return function(str){
            return eval(str);
        }.call(context, ' with(this) { ' + js + ' } ');
    }
    

    for implementation similar to "Dom-if"

    <template if="{{varInContext == ''}}"> ... </template>
    

    Example

    var myCtx = {table: 'Product', alias: 'ProductView'};
    evalInContext(' table == "" ', myCtx); //#false
    evalInContext(' alias == "ProductView" ', myCtx); //#true
    
    0 讨论(0)
提交回复
热议问题