这与另一个问题有关:
Last evaluated expression in Javascript
但我想提供更多有关我想做的事情的细节,并展示我最终是如何解决这个问题,就像一些用户在评论中所要求的那样。
我有一些由我的应用用户编写的Javascript片段。这个片段需要转到这样的模板:
var foo1 = function(data, options) {
<snippet of code written by user>
}
var foo2 = function(data, options) {
<snippet of code written by user>
}
...
表达式可能会有很大不同,例如:
data.price * data.qty
对于这样更复杂的事情:
if (data.isExternal) {
data.email;
} else {
data.userId;
}
函数返回的值应始终是最后计算的表达式。
在我们有这样的事情之前:
var foo1 = function(data, options) {
return eval(<snippet of code written by user>);
}
但是由于我们正在进行优化和更改,我们无法继续使用eval,但我们需要返回最后一次评估的表达式。
只需添加&#39;返回&#39;关键字不会起作用,因为表达式可以包含多个语句。所以我需要让这些函数返回最后评估的表达式。
限制和澄清:
答案 0 :(得分:0)
正如人们在Last evaluated expression in Javascript中指出的那样,在标准Javascript中无法获取最后一个评估表达式。
正如FelixKling所建议的那样,我最终做的就是操纵用户编写的脚本的AST。这样我就存储了用户编写的脚本和修改后的版本,这是我最终运行的版本。
为了操作AST,我使用了Rhino并基本上修改了所有EXPR_RESULT节点,以将结果存储在我最终在脚本末尾返回的变量中。以下是执行此操作的代码:
public class ScriptsManipulationService { private static final Logger logger = LoggerFactory.getLogger(ScriptsManipulationService.class);
public String returnLastExpressionEvaluated(String script) {
Parser jsParser = new Parser();
try {
AstRoot ast = jsParser.parse(script, "script", 1);
ast.getType();
ast.visitAll(new NodeVisitor() {
@Override
public boolean visit(AstNode node) {
if (node.getType() == Token.EXPR_RESULT) {
ExpressionStatement exprNode = (ExpressionStatement) node;
Assignment assignmentNode = createAssignmentNode("_returnValue", exprNode.getExpression());
assignmentNode.setParent(exprNode);
exprNode.setExpression(assignmentNode);
}
return true;
}
});
StringBuilder result = new StringBuilder();
result.append("var _returnValue;\n");
result.append(ast.toSource());
result.append("return _returnValue;\n");
return result.toString();
} catch (Exception e) {
logger.debug(LogUtils.format("Error parsing script"), e);
return script;
}
}
private Assignment createAssignmentNode(String varName, AstNode rightNode) {
Assignment assignmentNode = new Assignment();
assignmentNode.setType(Token.ASSIGN);
Name leftNode = new Name();
leftNode.setType(Token.NAME);
leftNode.setIdentifier(varName);
leftNode.setParent(assignmentNode);
assignmentNode.setLeft(leftNode);
rightNode.setParent(assignmentNode);
assignmentNode.setRight(rightNode);
return assignmentNode;
}
}
这样,如果您传递以下脚本:
data.price * data.qty;
你会回来的:
var _returnValue;
_returnValue = data.price * data.qty;
return _returnValue;
或者如果你通过:
var _returnValue;
if (data.isExternal) {
_returnValue = data.email;
} else {
_returnValue = data.userId;
}
return _returnValue;
请记住,我没有做过详尽的测试,并会随着时间的推移进行抛光,但这应该表明一般的想法。