我有以下javaScript“class”:
A = (function() {
a = function() { eval(...) };
A.prototype.b = function(arg1, arg2) { /* do something... */};
})();
现在让我们假设在eval()中我传递的字符串包含调用带有一些参数的表达式:
b("foo", "bar")
然后我得到b未定义的错误。所以我的问题是:如何在A类语境中调用eval?
答案 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
声明,除非您知道自己在做什么,但对于好奇,您可以这样做
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;
答案 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' }