Eval в области JavaScript, неопределенное значение - PullRequest
3 голосов
/ 14 июня 2011

Как часть моего механизма шаблонов, я должен уметь оценивать выражения в 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 ]

3 голосов
/ 14 июня 2011

Перехват доступа к несуществующим свойствам является нестандартным и невозможным в большинстве реализаций ECMAScript. Версия Rhino, поставляемая с JDK , похоже, предоставляет эту функцию , и SpiderMonkey может перехватывать произвольные вызовы методов , но не общий доступ к свойству.

Для ES Harmony есть предложение прокси , поэтому необходимость в такой функции была признана, но сейчас вам не повезло.

В качестве действительно уродливого обходного пути, вы можете отсканировать 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 голос
/ 14 июня 2011

Как уже отмечали другие, вы не можете сделать это с текущими реализациями JS, если вы не разберетесь хотя бы с базовым количеством анализа (для идентификаторов).

Я хотел бы добавить следующее: Возможноправильный ответ - ничего не делать и позволить JS просто потерпеть неудачу, поскольку она терпит неудачу прямо сейчас.Любое решение, которое вы попытаетесь реализовать, будет либо слишком сложным и / или медленным, либо полусгоревшей реализацией, которая оставляет дыры.Таким образом, может быть не стоит усилий и сложности, чтобы сделать ваш механизм шаблонов таким устойчивым.

Вы можете просто задокументировать: «Переменные / ссылки на свойства должны быть действительными. В противном случае выполучить ошибку. "и возложить ответственность на программистов.

0 голосов
/ 14 июня 2011

Если я правильно понимаю ваш вопрос, это должно сделать то, что вы хотите:

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/

...