I have following javaScript \"class\":
A = (function() {
a = function() { eval(...) };
A.prototype.b = function(arg1, arg2) { /* do something... */};
}
var evalWithinContext = function(context, code)
{
(function(code) { eval(code); }).apply(context, [code]);
};
evalWithinContext(anyContext, anyString);
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.
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
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
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
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
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)
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