这是javascript eval的一个很好的用途吗?

时间:2015-07-01 21:41:00

标签: javascript eval

我们有一个包含许多问题的表单,其中一些表单仅基于与JSON中发送的其他问题相关的动态逻辑显示。

每个问题的逻辑都类似于,但可能比以下更复杂:

如果显示以下内容:(quest1 == value1 OR quest1 == value2) AND (quest2 == value3 OR quest3 == value4)

简化的JSON示例:

[
    "AND",
    {
        "quest1": "value1,value2"
    },
    [
        "OR",
        {
            "quest2": "value3"
        },
        {
            "quest3": "value4"
        }
    ]
]

当父问题值发生变化时,似乎确定子问题可见性的一种方法是将给定问题的JSON解析为如上所述的JS友好语法,包括实际当前值并使用eval() 。还有更好的选择吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

我不会讲一讲为什么不使用eval。永远不要使用它。

也许您可以代表这样的问题的显示逻辑。这实际上取决于你的逻辑有多复杂以及什么是有用的表示。

var display_logic = {"operator":"and","conditions":
    [
    {"operator":"or","conditions":
        [
        {"operator":"equals","input_id":"question1","value":"val1"},
        {"operator":"equals","input_id":"question2","value":"val2"}
        ]
    },{"operator":"equals","input_id":"question3","value":"val4"}
    ]
};

编辑:我实际上更喜欢你提供的格式,所以我会改用它。下面的代码使用递归计算函数来评估结构为true还是false。然后,您可以根据需要轻松扩展逻辑运算符。

var visibility_logic = [
    "AND",
    {
        "quest1": "value1,value2"
    },
    [
        "OR",
        {
            "quest2": "value3"
        },
        {
            "quest3": "value4"
        }
    ]
];

//Interface to however you are accessing the answers
var qa_interface_func = function(question) {
    //E.g.
    //return $("#" + question).val();
    //For debugging, I will assume the answer is always "value3"
    return "value3";
};

//Recursive function which returns true or false based on the visibility logic and the current answers
function evaluateVisibility(item, qa_interface_func) {

    if (typeof item === "object") {
        if (Array.isArray(item)) {
            //Item is an array
            //Assume index 0 is the operator and the rest are conditions
            if (item.length < 3) {
                console.err("Bad structure", item);
                return false;
            }
            var operator = item[0];
            if (operator === "AND") {
                //All conditions need to be true to evaluate to true
                for(var index=1; index<item.length; index++) {
                    if (!evaluateVisibility(item[index], qa_interface_func)) {
                        return false;
                    }
                }
                return true;
            } else if (operator === "OR") {
                //1 condition needs to be true to evaluate to true
                for(var index=1; index<item.length; index++) {
                    if (evaluateVisibility(item[index], qa_interface_func)) {
                        return true;
                    }
                }
                return false;
            } else {
                console.err("Unknown operator", operator);
                return false;
            }
        } else {
            //Item is an object
            //All mappings must be true to evaluate to true
            for (var key in item) {
                var accepted_values = item[key].split(",");
                var current_value = qa_interface_func(key);
                if (accepted_values.indexOf(current_value) === -1) {
                    return false;
                }
            }
            return true;
        }
    } else {
        console.err("Must be an object or an array", item);
    }
}

if (evaluateVisibility(visibility_logic, qa_interface_func)) {
    console.log("Yes, show this question");
} else {
    console.log("No, hide this question");
}

上面的代码打印出&#34; No&#34;,但你可以说它&#34;是&#34;如果你摆弄逻辑阵列。

答案 1 :(得分:1)

我已经建立了这个确切的场景。我将问题和答案组装为树服务器端,然后通过Ajax调用将模型加载到页面中。每个Question对象都有问题文本和一个Answer对象数组,以及一个属性(最初为null)来保存任何选定的答案。每个Answer对象包含答案值和基于该答案的指向下一个Question的指针。我使用自引用的Knockout模板,在select中显示问题和答案列表。选择答案时,会触发显示下一个问题的if逻辑和可能的答案 - 如果:question.chosenAnswer()。

这里的关键是构建一个树并使用您正在使用的任何库或框架遍历它。

我现在正在打电话,当我有一个真正的键盘时会添加一些代码。

答案结构:{ answerId, answerValue, nextQuestion }

其中answerId是唯一的数字/ ID,用于标识树中唯一的路径以获得该答案。

问题树:

    {
    question: "Are there lots of questions?", // string
    chosenAnswer: null, // Answer
    answers: [
        {
            answerId: 1,
            answerValue: "Yes",
            nextQuestion: {
                question: "How many answers can there be?",
                chosenAnswer: null,
                answers: [
                    {
                        answerId: 2,
                        answerValue: "1",
                        nextQuestion: null // leaf
                    },
                    {
                        answerId: 4,
                        answerValue: "2",
                        nextQuestion: {
                            question: "How do you decide?",
                            chosenAnswer: null,
                            answers: [
                                {
                                    answerId: 5,
                                    answerValue: "Guess",
                                    nextQuestion: null // leaf
                                },
                                {
                                    answerId: 6,
                                    answerValue: "Think",
                                    nextQuestion: null // leaf
                                },
                            ]
                        }
                    },

                ]
            }
        },
        {
            answerId: 7,
            answerValue: "No" 
            nextQuestion: null // leaf
        },
    ]
}

你可以通过AJAX调用加载它,如果你使用jQuery for AJAX,你可以在.done(响应)中获得解析的JSON。如果没有,您可以使用JSON.parse()。不需要评估。我基于这种结构构建了我的knockout.js视图模型。

然后,只需使用您的框架(挖空,角度等)来根据所选答案管理增量显示。如何执行此操作取决于您的工具。

根据当前问题的答案数组填充我的选择下拉菜单。我在selectedAnswer属性上订阅(或观察),以便在选择叶子答案时(nextQuestion为null或未定义),我触发一个事件,该事件包括选择作为事件数据一部分的Answer对象。因此,我可以记录或回应最终选择的答案。

例如,这是我在knockout.js中使用的自引用模板:

<script id="qaTmpl" type="text/html">
    <div class="col-md-12 clearfix leaders">
        <div>
            <label class="question pull-left">{{question}}</label>
            <span>
                <select class="pull-right" data-bind="disable: $root.editBuffer().valueId(),
                    options: answers, optionsText: 'answer', optionValue: 'answer', value: chosenAnswer, optionsCaption:'Choose...'"></select>
            </span>
        </div>
    </div>
    <!-- ko if: $data && chosenAnswer&& chosenAnswer() && chosenAnswer().nextQuestion -->
    <!-- ko template: {name: 'qaTmpl', data: chosenAnswer().nextQuestion} --><!-- /ko -->
    <!-- /ko -->
</script>

我希望你明白这个主意。我希望我可以更具体,但很多实现细节都特定于您的框架和模板引擎。

答案 2 :(得分:0)

最好将数据和代码分开,在这种情况下,这意味着值“val1”,“val2”等可以通过json引入,但比较应该在js文件中编码。这可以通过灵活的方式来解决您的字段的动态特性。

相信我,使用已保存的代码片段来验证表单会成为维护的噩梦。信不信由我在编程生涯的早期实际上已经完成了它,这很糟糕。

使用正确的JSON解析器而不是eval。如果您无法将所需内容编码为JSON解析器将读取的内容,那么您不希望它出现在JSON中!

您是否有任何理由不能以这种方式读取您正在验证的数据?