JavaScript作用域评估,未定义值

JavaScript作用域评估,未定义值,javascript,scope,eval,Javascript,Scope,Eval,作为模板引擎的一部分,我需要能够计算JavaScript中的表达式,如: “first | | second”在某个对象的上下文中充当全局命名空间的角色。所以对象的属性应该被视为全局变量 到目前为止,我提出了这个函数: function scopedEval(str, scope) { var f = new Function("scope", "with(scope) { return (" + str + "); }"); return f(scope); } 一切都很好,

作为模板引擎的一部分,我需要能够计算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) );
生成错误“变量
第三个
未定义”。但我希望所有未知变量都被解析为
未定义
,而不是抛出错误。因此,“第三| |第一| |第二”应该再次屈服于
1

就我所知,这在现代JavaScript中是不可能的,但我可能会错过一些这样的问题。有什么想法吗


下面是一个示例:

如果我正确理解了您的问题,这应该可以满足您的要求:

function scopedEval(str, scope) {
   var toCheck = str.split(' || ');
    for(var i = 0; i < toCheck.length; ++i){
        if(scope[toCheck[i]])
            return scope[toCheck[i]];
    }
}
函数scopedEval(str,scope){
var toCheck=str.split(“| |”);
对于(变量i=0;i
可能需要在这里和那里进行更好的检查,但该方法适用于您的小提琴:)

拦截对不存在的属性的访问是非标准的,在大多数ECMAScript实现中是不可能的。Rhino版本随JDK一起提供,SpiderMonkey可以,但不能用于一般属性访问

对于ES Harmony来说,有一个很好的解决方案,所以对这样一个功能的需求已经得到承认,但是现在,你运气不好

作为一种非常糟糕的解决方法,您可以扫描
str
以查找(潜在)标识符,然后将它们添加到
范围中,如下所示:

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;
}
var-toks=str.match(/[A-Za-z_$][\w$]*/g);
对于(变量i=0;i
正如其他人所指出的,在当前的JS实现中,您无法做到这一点,除非您至少进行了基本的语法分析(针对标识符)

我想补充的是:也许正确的答案是什么都不做,让JS失败,因为它现在失败了。您试图实现的任何解决方案要么太复杂和/或太慢,要么是一个半生不熟的实现,留下漏洞。因此,让您的模板引擎如此健壮可能不值得付出如此多的努力和复杂性


您可以简单地记录“变量/属性引用必须有效。否则,您会出错。”并将责任推给程序员。

我相信
|
是一个通用示例,他希望对未定义变量的任何引用都不会引发错误。
first | | last
是一个通用示例,不幸的是,它可以是任何有效的JS表达式。做一些类似的事情,但有一个完整的编译器内置。是的,这是可能的,构建一个编译器。哇:
eval
在一个函数中使用
!马特@Koolic:它缺少一个
中断(~goto)
)。@Ates:为了完整性,它还应该使用
文档。write
元素写入页面,并使用
窗口创建几个弹出窗口。open
等。有时候web开发真的很简单(),你可以使用eval和词法范围来做类似的事情。我在回答中提供了一个Scope类,可能有助于检查令牌是否是有效标识符。类似于:
(/[a-z\$]\w+/i).test(toks[i])
。而
\b
$foo
拆分,因此如果这很重要,您需要找到解决方法…我已经对这个答案投了赞成票。但是,试图想出一个快速的解决方法而不是使用一个成熟的JS解析器只是打开了一个蠕虫罐头。需要考虑的边缘情况永远不会结束。也许正确的解决方案是咬紧牙关,而不是优雅地处理未定义的变量/属性。我相信jQuery模板也会失败。@Gijs,Ates:新的正则表达式问题应该少一些,但仍然不会处理unicode转义…我接受了这个答案,因为它原则上允许实现这个目标。但正如你所说,这是丑陋的,而且非常无效
eval()
与上面带有regexp的
组合太多了。在我的TIScript中,eval函数()具有签名
eval(str[,obj])
,它允许在
obj
命名空间中进行精确计算。然而,TIScript有
未定义属性(name,val)
,允许捕获对未定义属性的访问。不幸的是,在我的例子中提到“变量/属性引用必须有效”并不像在其他例子中那样有效。考虑胡桃夹或风筝模板,你可以在这里定义“代码> {{1 }} ..标记.. {{/}}} /COD>。完全不需要
eval()
就可以实现。如果
one
不存在,则跳过该部分,不会出错。我正在添加有条件的
if
构造:
{{one&&two}..markup..{{/}
。表达式
one&&two
应在不引发异常的情况下进行计算。