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

mno*_*tka 46 javascript

我有以下javaScript"class":

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

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

 b("foo", "bar")
Run Code Online (Sandbox Code Playgroud)

但后来我得到b没有定义的错误.所以我的问题是:如何在A类语境中调用eval?

Cam*_*eln 61

实际上你可以通过函数抽象完成这个:

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);
Run Code Online (Sandbox Code Playgroud)

所以你想要call的功能contexteval在该功能内运行.

奇怪的是,这似乎对我本地有用,但不适用于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);
}
Run Code Online (Sandbox Code Playgroud)

  • 您尝试过哪种浏览器(版本)?根据规范(以及在每个现代浏览器中),您在`example`中的`this`值得到`undefined`(或在草率模式函数中的全局窗口对象),它不起作用. (6认同)

use*_*385 29

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

var result = function(str){
  return eval(str);
}.call(context,somestring);
Run Code Online (Sandbox Code Playgroud)

巴姆.

  • 如果你打算投票,给出一个理由. (8认同)
  • 多么优雅的解决方案 (3认同)
  • “somestring”是您希望使用 eval 命令运行的代码。请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call (2认同)
  • 请注意,somestring中的表达式必须使用“ this”来访问上下文属性,例如this.property。否则,您将获得未定义的属性ReferenceError。var context = {'live-usa':'no','alcohol':'never','height':'65','weight':'140'}; var expression =“ this.height ==” || this.weight ==“”; var result = function(str){return eval(str); } .call(上下文,表达式);//在这种情况下返回false。 (2认同)

eve*_*Guy 17

编辑

即使eval.call和eval.apply不强制正确传递上下文,您也可以使用闭包来强制eval在所需的上下文中执行,如@Campbeln和@ user3751385的答案中所述

我原来的答案

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

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

有关更多信息,请在此处查看这篇精彩的文章

  • 嗯...这并不完全正确。您可以在特定的上下文中执行`eval`,在其中传递`this` ===`theContext`(例如`{neek:true}`)。诀窍是您必须另一个调用.val然后调用eval的函数,而不能直接按示例中的.call调用eval来完成。在下面查看我有关如何完成此操作的答案。 (2认同)

ben*_*ael 8

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

    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);
    }
Run Code Online (Sandbox Code Playgroud)

with是在功能中创建块范围的尝试失败,这是ES6的let目的.(但不完全是,打开并阅读资源链接)

  • 我觉得这个答案绝对没错.with语句是解决此问题的完美方案.只有当你在任何地方或大范围内使用'with'时,它才会产生歧义问题.:) (3认同)
  • 这也是唯一允许您在不需要“this”的情况下引用值的解决方案。 (2认同)

Loï*_*oix 7

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

您可能可以跳过这一部分,但要解释情况……这是一个更完整的答案。

调用 eval 很糟糕......在这里我正试图做到这一点......不是因为我想要而是因为有人强迫我这样做......我的另一个选择是编译提取物和AST并最终评估a的上下文价值...但 eval 除了其自身的邪恶性质之外,它确实是完成任务的工具...

所以我们开始了,mdn 文档:

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

简而言之, eval 曾经可以工作,现在它变得更加难以使用,因为评估的上下文将成为全局上下文,因此在某些情况下不可能获得this. 并且由于某些原因,它看起来似乎无法this使用此问题的答案获得as 评估上下文。所以进一步阅读我们到达了文章的第二部分..

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

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

好!

所以看代码的接缝非常好... 大多数例子只是简单地创建一个函数调用它并把它扔掉。这几乎就是 eval 的工作方式,所以你也可以这样做......

但对我来说, 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};
  }                                                                                                                   
  `
}
Run Code Online (Sandbox Code Playgroud)

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

该函数的第一行通过从作为参数传递的上下文中获取值来生成局部范围内声明变量的列表。

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

let a = context['a'], b = context['b'];
Run Code Online (Sandbox Code Playgroud)

第二行是您要评估的上下文,例如“a + b”

它将呈现以下代码:

return a + b
Run Code Online (Sandbox Code Playgroud)

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

function make_context_evaluator(eval_string, context) {
  let template = create_context_function_template(eval_string, context)
  let functor = Function(template)
  return functor()
}
Run Code Online (Sandbox Code Playgroud)

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

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

关于它的好处是,如果您想继续使用评估器,因为您知道您不会对评估上下文进行太多更改......然后您可以保存评估器并在不同的上下文中重用它..

在我的情况下,它是根据一些记录评估上下文,因此字段集相同但值不同......因此可以重用该方法而无需编译多个方法......另一方面,据说它比使用更快eval,我们没有评估任何东西。如果传递给 的值Function会尝试在其范围之外使用事物......它的危害会小于eval......例如,它可以访问全局范围但不应该访问词法范围。换句话说......你被限制在全局范围内,并且 this 传递给调用参数。

然后,如果您真的想将它用作类似 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)
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*maa 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

  • 停止阅读第一篇文章"eval是方便的",第二篇文章没有提到eval的任何用例,而是如何在普通新手错误使用eval的情况下替换eval的使用. (2认同)
  • @Rocket:是的,很少见,当然是在浏览器环境中.在NodeJS之类的东西中,它的模块系统通过将文件中的代码连接到一个开始和结束字符串,然后评估它来工作.jsFiddle可能是另一个例子,但我假设.是的,我假设`new Function`使用`eval`,或者至少与eval共享代码.虽然存在差异. (2认同)
  • @Rocket:不确定这是否是一个浏览器环境,但可能是一个安全的赌注.顺便说一句,你的jsFiddle没有工作,因为你没有传递`window`对象. (2认同)

Ila*_*ior 5

这解决了我的问题。

 function evalInContext(js, context) {
    return function(str){
        return eval(str);
    }.call(context, ' with(this) { ' + js + ' } ');
}
Run Code Online (Sandbox Code Playgroud)

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

<template if="{{varInContext == ''}}"> ... </template>
Run Code Online (Sandbox Code Playgroud)

例子

var myCtx = {table: 'Product', alias: 'ProductView'};
evalInContext(' table == "" ', myCtx); //#false
evalInContext(' alias == "ProductView" ', myCtx); //#true
Run Code Online (Sandbox Code Playgroud)