在特定的上下文中调用eval()

时间:2011-12-06 16:13:53

标签: javascript

我有以下javaScript“class”:

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

现在让我们假设在eval()中我传递的字符串包含调用带有一些参数的表达式:

 b("foo", "bar")

然后我得到b未定义的错误。所以我的问题是:如何在A类语境中调用eval?

15 个答案:

答案 0 :(得分:53)

实际上你可以通过函数抽象实现这一点:

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);

所以你call使用你想要的context函数并在该函数中运行eval

奇怪的是,这似乎在我本地工作,但不在Plunkr上工作!?

对于简洁(可以说是多汁的)版本,您可以逐字复制到您的代码中,使用它:

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);
}

答案 1 :(得分:26)

如何在给定的上下文中调用eval? 3个字。使用封闭。

var result = function(str){
  return eval(str);
}.call(context,somestring);

的Bam

答案 2 :(得分:16)

修改

即使eval.call和eval.apply没有强制正确传递上下文,你可以使用闭包来强制eval在@Campbeln和@ user3751385的答案中提到的所需上下文中执行< / p>

我的原始答案

这是不可能的。 Eval仅在本地上下文中使用(直接使用)或在全局上下文中调用(即使您使用eval.call)。

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

有关详情,请参阅此精彩文章here

答案 3 :(得分:8)

绝对不是正确答案,请不要使用with声明,除非您知道自己在做什么,但对于好奇,您可以这样做

实施例

&#13;
&#13;
    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);
    }
&#13;
&#13;
&#13;

with是在函数内创建块作用域失败的尝试,类似于ES6's let的目的。 (但不完全是,打开并阅读资源链接)

答案 4 :(得分:6)

这是一篇讨论在不同背景下运行eval()的文章:

http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context

通常您使用eval.call()eval.apply()

以下是有关eval()及其使用案例的信息:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/eval

答案 5 :(得分:6)

所以我们现在是2020年,我有这个要求,不幸的是,大多数答案根本不适合该任务。

您可能可以跳过此部分,但要说明情况...这是更完整的答案。

调用eval不好...在这里,我正试图做到这一点。.不是因为我想要,而是因为有人强迫我这样做...我的另一个选择是编译extract和AST并最终评估值的上下文...但是,评估本身除了具有邪恶的性质外,它还是完成任务的工具...

因此,我们去看看mdn文档:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

简而言之,eval过去一直有效,现在变得更加难以使用,因为评估上下文将成为全局上下文,因此在某些情况下无法获得this。并且由于某些原因,使用该问题的答案似乎无法获得this作为评估上下文。 因此,进一步阅读我们将到达本文的第二部分。

文章的第二部分以“从不使用eval()!” 开始,收到消息!进一步阅读,我们得出以下结论:

幸运的是,有一个很好的替代eval()的方法:只需使用 window.Function()。

好!

所以看一下接缝非常好的代码...大多数示例只是创建一个函数调用它并扔掉它。这几乎是eval的工作原理,因此您也可以这样做...

但是对我而言,评估上下文可以被重用并且可能经常被重用,所以我想到了这一点。

function create_context_function_template(eval_string, context) {
  return `
  return function (context) {
    "use strict";
    ${Object.keys(context).length > 0
      ? `let ${Object.keys(context).map((key) => ` ${key} = context['${key}']`)};`
      : ``
    }
    return ${eval_string};
  }                                                                                                                   
  `
}

这将编译一个函数,该函数接收在给定特定上下文的情况下要评估的上下文。在您知道评估上下文将始终包含一组特定键的情况下非常有用。

函数的第一行通过从作为参数传递的上下文中获取值,在本地范围内生成已声明变量的列表。

这将在给定上下文的情况下呈现如下所示的JS代码:{a: 1, b: 2}

let a = context['a'], b = context['b'];

第二行是您要评估的上下文,因此对于类似“ a + b”的内容

它将呈现以下代码:

return a + b

总而言之,有这个实用程序方法:

function make_context_evaluator(eval_string, context) {
  let template = create_context_function_template(eval_string, context)
  let functor = Function(template)
  return functor()
}

只需将其包装起来并返回我们需要的函子...

let context = {b: (a, b) => console.log(a, b)}
let evaluator = make_context_evaluator("b('foo', 'bar')", context)
let result = evaluator(context)

关于它的好处是,如果您想继续使用评估程序,因为您知道自己不会对评估上下文进行太多更改...那么您可以保存评估程序并在其他上下文中重用它。 >

在我的情况下,它是基于一些记录来评估上下文,因此字段集相同,但值不同...因此,该方法可以重复使用,而不必编译多个方法...在另一个方法上另外,据说它比使用eval更快,而且我们也没有逃避任何事情。而且,如果传递给Function的值将尝试在其范围之外使用东西,那么它的危害将小于eval ...例如,它可以访问全局范围,但不应无法访问词汇范围。换句话说...您仅限于全局范围,并且此范围传递给了call参数。

然后,如果您真的想将其用作类似eval的函数,则可以执行以下操作:

function create_context_function_template(eval_string, context) {
  return `
  return function (context) {
    "use strict";
    ${Object.keys(context).length > 0
      ? `let ${Object.keys(context).map((key) => ` ${key} = context['${key}']`)};`
      : ``
    }
    return ${eval_string};
  }                                                                                                                   
  `
}

function make_context_evaluator(eval_string, context) {
  let template = create_context_function_template(eval_string, context)
  let functor = Function(template)
  return functor()
}

function eval_like(text, context={}) {
   let evaluator = make_context_evaluator(text, context)
   return evaluator(context)
}

答案 6 :(得分:2)

var evalWithinContext = function(context, code)
{
    (function(code) { eval(code); }).apply(context, [code]);
};
evalWithinContext(anyContext, anyString);

答案 7 :(得分:1)

另一个Bam!

eval('(function (data) {'+code+'})').call(selector,some_data);

此示例将保留您的上下文并发送一些数据。就我而言,是一个 DOM选择器

答案 8 :(得分:1)

您可以使用我的图书馆https://github.com/marverix/meval

const meval = require('meval');

console.log(
  meval('item.a + item.b * 5', { item: { a: 2, b: 3 } })
);

// outputs: 17

答案 9 :(得分:0)

对我有用的是使用Function构造函数并在指定的上下文中调用它:

var o = {
  x: 10
}

(new Function(`console.log(this.x)`)).call(o);

这种方式在浏览器的控制台中不起作用,但在其他地方也可以。

答案 10 :(得分:0)

这解决了我的问题。

dst

用于类似于“ Dom-if”的实现

dst

示例

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

答案 11 :(得分:0)

包括上下文,函数和表达式。上下文必须是平面结构(无嵌套元素),并且函数必须在字符串表达式内称为“ fn”。答案打印11:

var expression = "fn((a+b)*c,2)";
var context = { a: 1, b: 2, c: 3 };
var func = function(x,y){return x+y;};

function evaluate(ex, ctx, fn) {
return eval("var "+JSON.stringify(ctx).replace(/["{}]/gi, "").replace(/:/gi, "=")+", fn="+fn.toString()+";"+ex);
}

var answer = evaluate(expression, context, func);
console.log(answer);

答案 12 :(得分:0)

我在Angular中苦苦挣扎了一段时间,发现这个答案最有用。我试图实现一些使用'with'的现有代码,但严格不允许。 我的“刀叉”解决方案不必使用“ this”。在我要评估的表达式内,避免使用“ with”和“ eval”:

let evalInContext = function (js, context) {
    let keys = Object.keys(context);
    //let code = 'function it(){';
    let code = '';
    for (let i = 0; i < keys.length; i++){
        code += 'let '+keys[i]+' = window._evalincontextobj.'+keys[i]+';\n';
    }
    code += 'return (';
    code += js;
    code += ')';//}\n return it();';
    window['_evalincontextobj'] = context;
    let res = Function(code)();
    console.log(js+' = '+res);
    delete window['_evalincontextobj'];
    return res;
}

这适用于(watched ==='hello')这样的表达式,其中'watched'是上下文的成员。

答案 13 :(得分:0)

伙计们,我想我有明确的答案。它可同时用于JavaScript(浏览器)和NodeJ。

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}

在Node v12.16.1,Node v14.7.0,Firefox v79.0和Google Chrome v84.0.4147.105上进行了测试

答案 14 :(得分:0)

对于 node.js env,您可以使用 safe-eval 在上下文中进行评估,例如这个(取自 https://www.npmjs.com/package/safe-eval):

// your own context API - access to Node's process object and a custom function
var code = '{pid: process.pid, apple: a()}'
var context = {
  process: process,
  a: function () { return 'APPLE' }
}
var evaluated = safeEval(code, context) // { pid: 16987, apple: 'APPLE' }