Javascript 在特定上下文中调用 eval()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8403108/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
calling eval() in particular context
提问by mnowotka
I have following javaScript "class":
我有以下javaScript“类”:
A = (function() {
a = function() { eval(...) };
A.prototype.b = function(arg1, arg2) { /* do something... */};
})();
Now let's assume that in eval() I'm passing string that contains expression calling b with some arguments:
现在让我们假设在 eval() 中我传递的字符串包含使用一些参数调用 b 的表达式:
b("foo", "bar")
But then I get error that b is not defined. So my question is: how to call eval in context of class A?
但是后来我得到了 b 未定义的错误。所以我的问题是:如何在 A 类的上下文中调用 eval?
回答by Campbeln
Actually you canaccomplish 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.
因此,您可以使用call
所需的函数context
并eval
在该函数内运行。
Oddly, this seems to be working for me locally but not on Plunkr!?
奇怪的是,这似乎在本地对我有用,但在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".
编辑:不要混淆this
和“范围”。
//# 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:
为了缩小差距,这不是 OP 提出的问题,它使用的是with
,正如 MDN 所说:
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.
不推荐使用 with 语句,因为它可能是混淆错误和兼容性问题的根源。有关详细信息,请参阅下面“描述”部分中的“歧义反义词”段落。
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.
但它确实有效,而且还不算太“坏”(不管这意味着什么),只要人们意识到这种调用可能会带来的奇怪之处。
回答by user3751385
How to call eval in a given context? 3 words. Use a closure.
如何在给定的上下文中调用 eval?3个字。使用闭包。
var result = function(str){
return eval(str);
}.call(context,somestring);
Bam.
砰。
回答by everconfusedGuy
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
即使 eval.call 和 eval.apply 不强制正确传递上下文,您也可以使用闭包来强制 eval 在@Campbeln 和@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).
这不可能。eval 仅在本地上下文(直接使用)或全局上下文(即使您使用 eval.call)中调用。
For example,
a = {};
eval.call(a, "console.log(this);"); //prints out window, not a
例如,
a = {};
eval.call(a, "console.log(this);"); //prints out window, not a
For more information, look at this greatarticle here
有关更多信息,请在此处查看这篇很棒的文章
回答by bentael
definitelynot 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
绝对不是正确的答案,请不要使用with
语句,除非您知道自己在做什么,但出于好奇,您可以这样做
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)
回答by Mikko Ohtamaa
Here is an article which discussing running eval()
in different contexts:
这是一篇讨论eval()
在不同上下文中运行的文章:
http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
Usually you do it with eval.call()
or eval.apply()
.
通常你用eval.call()
或来做eval.apply()
。
Here is also information regarding eval()
and its use cases:
以下是有关eval()
及其用例的信息:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/eval
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/eval
回答by Ilario Junior
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"
用于类似于“Dom-if”的实现
<template if="{{varInContext == ''}}"> ... </template>
Example
例子
var myCtx = {table: 'Product', alias: 'ProductView'};
evalInContext(' table == "" ', myCtx); //#false
evalInContext(' alias == "ProductView" ', myCtx); //#true
回答by Eigendrew
var evalWithinContext = function(context, code)
{
(function(code) { eval(code); }).apply(context, [code]);
};
evalWithinContext(anyContext, anyString);
回答by marverix
You can use my library https://github.com/marverix/meval.
您可以使用我的库https://github.com/marverix/meval。
const meval = require('meval');
console.log(
meval('item.a + item.b * 5', { item: { a: 2, b: 3 } })
);
// outputs: 17
回答by Lo?c Faure-Lacroix
So here we are in 2020 and I had this requirement and unfortunately most of the answers are simply not fit for the task.
所以我们在 2020 年,我有这个要求,不幸的是,大多数答案根本不适合这项任务。
You can probably skip this part but to explain the situation... here's a more complete answer.
您可能可以跳过这一部分,但要解释情况……这是一个更完整的答案。
Calling eval is bad... And here I am trying to do exactly that.. Not because I want but because someone forced me to do that... my other option would be to compile extract and AST and eventually evaluate the context of a value... But eval is exactly the tool for the task besides its own evil nature...
调用 eval 很糟糕......在这里我正试图做到这一点......不是因为我想要而是因为有人强迫我这样做......我的另一个选择是编译提取物和AST并最终评估a的上下文价值...但 eval 除了其自身的邪恶性质之外,它确实是完成任务的工具...
So here we go, the mdn documentation:
所以我们开始了,mdn 文档:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
In short, eval used to work and now it's made more difficult to use as the context of evaluation will become the global context so in some case it's impossible to get this
. And for some reasons, it didn't look like it could get the this
as evaluation context using the answers from this question.
So reading further we reach the second part of the article..
简而言之, eval 曾经可以工作,现在它变得更加难以使用,因为评估的上下文将成为全局上下文,因此在某些情况下不可能获得this
. 并且由于某些原因,它看起来似乎无法this
使用此问题的答案获得as 评估上下文。所以进一步阅读我们到达了文章的第二部分..
Second part of the articles starts with "Never use eval()!", message received! Reading further we come to this:
文章的第二部分以“永远不要使用 eval()!”开头。, 收到消息!进一步阅读我们得出以下结论:
Fortunately, there's a very good alternative to eval(): simply using window.Function().
幸运的是,有一个非常好的 eval() 替代方法:只需使用 window.Function()。
Ok good!
好!
So looking at the code that seamed very good... Most of the example simply create a function call it and throw it away. This is pretty much how eval works so you could probably do that too...
所以看代码的拼接非常好......大多数示例只是创建一个函数调用它并将其扔掉。这几乎就是 eval 的工作方式,所以你也可以这样做......
But for me, the eval context can be reused and potentially quite often so I came up with 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};
}
`
}
This compiles a function that receives a context to be evaluated given a specific context. It's useful for cases where you know that the evaluation context will always contains a certain set of keys...
这将编译一个函数,该函数接收要在给定特定上下文的情况下进行评估的上下文。这对于您知道评估上下文将始终包含一组特定键的情况很有用......
The first line of the function generate a list of declared variables on the local scope by taking values from the context passed as a parameter.
该函数的第一行通过从作为参数传递的上下文中获取值来生成局部范围内声明变量的列表。
This will render JS code that look like this given a context: {a: 1, b: 2}
这将在给定上下文的情况下呈现如下所示的 JS 代码: {a: 1, b: 2}
let a = context['a'], b = context['b'];
The second line is the context you want to evaluate so for something like this 'a + b'
第二行是您要评估的上下文,例如“a + b”
It would render the following code:
它将呈现以下代码:
return a + b
All in all, there is this utility method:
总而言之,有这个实用方法:
function make_context_evaluator(eval_string, context) {
let template = create_context_function_template(eval_string, context)
let functor = Function(template)
return functor()
}
That simply wrap it up and return the functor we need...
这只是将它包装起来并返回我们需要的函子......
let context = {b: (a, b) => console.log(a, b)}
let evaluator = make_context_evaluator("b('foo', 'bar')", context)
let result = evaluator(context)
The nice thing about it is that if you want to keep using the evaluator as you know you won't be changing the evaluation context much... Then you can save the evaluator and reuse it with different context..
关于它的好处是,如果您想继续使用评估器,因为您知道您不会对评估上下文进行太多更改......然后您可以保存评估器并在不同的上下文中重用它..
In my case it's to evaluate a context based on some records so the field set is the same but the values are different... So the method can be reused without having to compile more than one method... On the other plus side, it's supposedly faster than using eval
and we're not evaling anything. And if the value passed to the Function
would try to used thing outside of its scope... it would be less harmful than eval
... For example, it has access to the global scope but shouldn't have access to the lexical scope. In other words...You're limited to the global scope, and the this passed to the call argument.
在我的情况下,它是根据一些记录评估上下文,因此字段集相同但值不同......因此可以重用该方法而无需编译多个方法......另一方面,据说它比使用更快eval
,我们没有评估任何东西。如果传递给 的值Function
会尝试在其范围之外使用事物......它的危害会小于eval
......例如,它可以访问全局范围但不应该访问词法范围。换句话说......你被限制在全局范围内,并且 this 传递给调用参数。
And then if you really wanted to use it as an eval like function you could do 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)
}
回答by Artur
Another Bam!
另一个巴姆!
eval('(function (data) {'+code+'})').call(selector,some_data);
This example will keep yours context and send some data. In my case, is a some DOM selector
此示例将保留您的上下文并发送一些数据。就我而言,是一些DOM 选择器