不使用此关键字的上下文中的javascript eval

时间:2016-10-18 12:10:58

标签: javascript eval

我正在尝试在特定上下文中执行eval。我发现答案here很有用。但是,我在Chrome版本53.0.2785.143 m中收到以下行为。没试过其他浏览器。我正在使用的代码如下:

function evalInContext(js, context) {
    return function() { return eval(js); }.call(context);
}


console.log(evalInContext('x==3', { x : 3})) // Throws
console.log(evalInContext('this.x==3', { x : 3})) // OK

但是我期望第一次打电话给evalInContext不要扔。有什么想法可能会发生这种情况吗?

5 个答案:

答案 0 :(得分:6)

虽然我推荐@trincot提供的答案,特别是伟大的链接。我在这里发布我遇到的问题的解决方案

function evalInContext(scr, context)
{
    // execute script in private context
    return (new Function( "with(this) { return " + scr + "}")).call(context);
}

with(this)表达式允许context对象的成员变量出现在表达式scr的执行范围内。

this answer归功于类似的问题

答案 1 :(得分:3)

这是另一种方法(用ES6编写):

lst <- strsplit(df[,1], ", ")
do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
#   [,1]     [,2]      
#a "John"   "3 years" 
#b "Mokobe" "11 years"
#c "Ivan"   NA       

为乔纳斯·威尔姆斯提供答案。

这是我的解释,因为我最初并不了解它是如何工作的:

 (new Function(...Object.keys(context), codeYouWantToExecute))(...Object.values(context));

与创建函数并将其分配给let example = new Function('a', 'b', 'return a+ b') 相同:

example

之后,您可以像这样调用function(a,b) { return a + b } example返回8。

但是,假设您不想将example(2,6)创建的函数分配给变量,而是想立即调用它。

然后您可以执行以下操作:

new Function

本文顶部的代码段实质上是在做同样的事情。它使用散布运算符来传递new Function('a', 'b', 'return a+ b')(2,6) 对象的键,如下所示: context。然后,它将调用新创建的函数,并使用传播运算符传递与每个键对应的值。

最后,这是编译到ES5的答案:

new Function(key1, key2, key3... lastkey, codeYouWantToExecute)

答案 2 :(得分:2)

范围和背景不一样

解析变量x的方式与上下文无关。它由范围规则解决:任何闭包是否定义了该变量?如果没有,请查看全局对象。在任何时候都不会通过查看上下文来解析变量。

您可以查看this article

行为并非特定于eval,与其他功能相同:

&#13;
&#13;
"use strict";

var obj = { x : 3};
var y = 4;

function test() {
  console.log(this.x); // 3
  console.log(typeof x); // undefined
}

test.call(obj);

function test2() {
  console.log(this.y); // 4
  console.log(typeof y); // number
}

test2.call(window);
&#13;
&#13;
&#13;

答案 3 :(得分:0)

这将在给定的上下文中计算表达式,而无需在vars前面加上“ this”。

有警告,但工作正常。

还可以在表达式中合并自定义函数。

只需调用一个“求值”函数,传入您的表达式,上下文和一个可选函数即可。

上下文必须是平面结构(无嵌套元素),并且函数必须在字符串表达式内称为“ 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);

答案 4 :(得分:0)

无法发表评论,所以我发帖,Joe 的回答很棒,但如果字符串包含多个语句(如 x++; y++; x+y;),则永远不会执行 y++ 部分,因为它在第一个语句处返回。

通过此修改,所有语句都将被执行,最后一条语句将作为返回值。

<块引用>
function evalInScopeAndContext(scr, scopeAndContext)
{
    // execute script in private context
    return (new Function( "with(this) { return eval('" + scr + "'); }")).call(scopeAndContext);
}

我还更改了参数名称,因为该参数既用作作用域又用作上下文,它们是不同的东西。

警告 1:

使用此函数时,this.x 将等于 x 且无法更改,因为范围的 this 属性(如果存在)将被遮蔽。

如果你执行 evalInScopeAndContext('this', {a:1, b:2, this:3}) 答案将是 {a:1, b:2, this:3} 而不是 3

要访问属性 this,您必须改为编写 this.this,我认为它无法修复。

警告 2:

外部作用域(从这个函数的调用者到 window)可以被访问和修改,除非被作用域对象遮蔽。

因此,如果您计划执行诸如 location = 'house'; 之类的操作,但忘记在作用域对象中插入 location 键,您将执行 window.location = 'house' 并可能造成损坏。

相反,this.location = 'house'; 始终是安全的,因为 this 始终存在并且只会将 location 键添加到提供的范围对象中,因此您可能希望始终使用 this. 作为前缀