JavaScript范围的eval,未定义的值

时间:2011-06-14 06:55:39

标签: javascript scope eval

作为模板引擎的一部分,我需要能够在JavaScript中评估表达式,如: "first || second"在某个对象服务全局命名空间角色的上下文中。所以对象的属性应该被视为全局变量。

到目前为止,我想出了这个功能:

function scopedEval(str, scope) {
   var f = new Function("scope", "with(scope) { return (" + str + "); }");
   return f(scope);  
}

一切都很好,我可以运行它:

var scope = { first:1, second:2 };
var expr1  = "first || second";
alert( scopedEval(expr1,scope) );

它提醒我1

范围对象中未定义的变量的唯一问题。这样:

var expr2  = "third || first || second";
alert( scopedEval(expr2,scope) );

生成错误“未定义变量third”。但我希望将所有未知变量解析为undefined而不是抛出错误。所以“第三||第一||第二”应该再次屈服于1

至于我的知识,这样的事情在现代JavaScript中是不可能的,但我可能会错过这样的问题。有什么想法吗?

以下是一个示例:http://jsfiddle.net/nCCgT/

3 个答案:

答案 0 :(得分:3)

拦截对不存在的属性的访问是非标准的,大多数ECMAScript实现都不可能。随JDK seems to provide this feature和SpiderMonkey一起提供的Rhino版本可以catch arbitrary method calls,但不能进行常规属性访问。

ES Harmony有一个proxy proposal,所以对此功能的需求已得到承认,但是现在,你运气不好。

作为一种非常难看的解决方法,您可以扫描str(潜在)标识符并将其添加到scope,如下所示:

var toks = str.match(/[A-Za-z_$][\w$]*/g);
for(var i = 0; i < toks.length; ++i) {
    if(!(toks[i] in scope))
        scope[toks[i]] = undefined;
}

答案 1 :(得分:1)

正如其他人所说,你不能用当前的JS实现来做到这一点,除非你至少进行了大量的解析(用于标识符)。

我想补充的是:也许正确的答案是不要做任何事情让JS失败,因为它现在失败了。您尝试实施的任何解决方案都将过于复杂和/或过于缓慢,或者是一个留下漏洞的半成品实现。因此,使您的模板引擎 健壮可能不值得花费精力和复杂性。

您可以简单地记录,“变量/属性引用必须有效。否则,您将收到错误。”并把责任放在程序员身上。

答案 2 :(得分:0)

如果我理解你的问题,这应该做你想要的:

function scopedEval(str, scope) {
   var toCheck = str.split(' || ');
    for(var i = 0; i < toCheck.length; ++i){
        if(scope[toCheck[i]])
            return scope[toCheck[i]];
    }
}

可能需要在这里和那里更好地检查,但该方法适用于你的小提琴:) http://jsfiddle.net/nCCgT/1/