JavaScript-使用eval()作为条件-是否正确?

时间:2019-02-17 07:12:39

标签: javascript json

我有使用filter搜索的JSON数据:

myJsonData.filter(function (entry) { return (entry.type === 'model' || entry.type === 'photographer' ); });

现在,我没有创建返回条件,而是创建了一个类似的字符串(因为我想拥有一个预先创建的搜索条件列表),然后使用eval(),这样:

myJsonData.filter(function () { return eval(stringToSearch) ; });

这似乎起作用。但是,我只想确认一下,这是正确的用法吗?这样做有任何风险/问题吗?

我想灵活地进行任何类型的搜索,例如:

myJsonData.filter(function (entry) { 
   return (entry.type === 'model' || entry.type === 'photographer') 
          && entry.level.indexOf('advanced') > -1 ; 
});

这就是为什么我制作了一个单独的类来创建该字符串的原因。

3 个答案:

答案 0 :(得分:8)

为避免使用eval,您可以将用户输入(通过按钮或其他方式)转换为过滤器。这些过滤器每个数据属性(即每个位置,类型,级别等)将具有一个过滤器。这些过滤器之一可以是值列表,也可以是自由文本单个值。

这是一个带有示例数据集的示例实现,没有任何性感的输入/输出小部件,...仅是演示过滤算法的最低要求:

// The sample data to work with:
var data = [
    { location: "ny", type: "model", level: "advanced", name: "Jack" },
    { location: "ny", type: "model", level: "beginner", name: "Fred" },
    { location: "sf", type: "model", level: "experienced", name: "Helen" },
    { location: "sf", type: "photographer", level: "is advanced", name: "Stacy" },
    { location: "sf", type: "photographer", level: "advanced experience", name: "Joy" },
    { location: "ny", type: "photographer", level: "beginner++", name: "John" },
    { location: "sf", type: "model", level: "no experience", name: "Jim" },
    { location: "ny", type: "photographer", level: "professional", name: "Kay" },
];

// A global variable to maintain the currently applied filters
var filters = { type: [], location: [], level: "" };

// Capture user selections and translate them to filters
// Type 1: multiple selections from a closed list of values:
document.querySelector("#seltypes").addEventListener("change", function() {
    filters.type = [...this.options].filter(option => option.selected).map(option => option.value);
    refresh();
});

document.querySelector("#sellocations").addEventListener("change", function() {
    filters.location = [...this.options].filter(option => option.selected).map(option => option.value);
    refresh();
});

// Type 2: free text filter:
document.querySelector("#inplevel").addEventListener("input", function() {
    filters.level = this.value;
    refresh();
});

function refresh() {
    // This is the actual filtering mechanism, making use of the filters variable
    let result = data;
    for (let prop in filters) {
        let value = filters[prop];
        if (!value.length) continue; // If this filter is empty: don't filter
        result = Array.isArray(value)
            ? result.filter(entry => value.some(type => entry[prop] === type))
            : result.filter(entry => entry[prop].includes(value));
    }
    // No effort done here on the output format: just JSON :-)
    document.querySelector("#output").textContent = JSON.stringify(result, null, 2);
}

// Start 
refresh();
td { vertical-align: top }
<b>Filters (Ctrl to multi select):</b>
<table>
<tr><th>Types</th><th>Locations</th><th>Level</th></tr>
<tr><td>
  <select multiple id="seltypes" size="2">
    <option value="model">Model</option>
    <option value="photographer">Photographer</option>
  </select>
</td><td>
  <select multiple id="sellocations" size="2">
    <option value="ny">New York</option>
    <option value="sf">San Francisco</option>
  </select>
</td><td>
  <input id="inplevel">
</td></tr></table>

<pre id="output"></pre>

答案 1 :(得分:1)

您可以使用输出中想要的值创建一个对象,然后进行过滤。

if条件下,我检查是否应用了高级过滤器。如果也应用了&&条件检查。如果没有,那么我将检查正常情况。

let data  = [{type: 'model', level:'advanced'}, {type:'photographer',level:'advanced'},{type:'random', level:'random'}, {type:'model', value:'without level'}]
let checks = {'model':true, 'photographer':true, advanced:['advanced']}

let output = data.filter(( {type,level} ) => {
  if(checks.advanced && checks.advanced ){
     return checks[type] && checks.advanced.includes(level)
  } else {
    return checks[type]
  }
} )

console.log(output)

答案 2 :(得分:-1)

使用eval并没有错。这是您可以完成的三种方法。

当然还有其他方法可以做到,但这是一种动态得多的方法。

    // The sample data to work with:
    var data = [
        { location: "ny", type: "model", level: "advanced", name: "Jack" },
        { location: "ny", type: "model", level: "beginner", name: "Fred" },
        { location: "sf", type: "model", level: "experienced", name: "Helen" },
        { location: "sf", type: "photographer", level: "is advanced", name: "Stacy" },
        { location: "sf", type: "photographer", level: "advanced experience", name: "Joy" },
        { location: "ny", type: "photographer", level: "beginner++", name: "John" },
        { location: "sf", type: "model", level: "no experience", name: "Jim" },
        { location: "ny", type: "photographer", level: "professional", name: "Kay" },
    ];

    // Example 1
    var searchOne = function(a ){
        return a.location == "ny";
    }

    // Example two: an attribute
    var searchTwo = new Function("a", test.getAttribute("condition"));

    // Example three: filter list, need much work.... to handle operator      // And, OR
    var searchThree = [
        { field: "location", key: "=", value:"ny"  }]

    console.log("example 1")
    console.log(data.filter(searchOne))

    console.log("example 2")
    console.log(data.filter(searchTwo))

    console.log("example 3")
    console.log(data.filter((a)=> {
        var result = true;
        searchThree.forEach((x)=> {
            var v = a[x.field];
            if (x.key == "=")
                result = (v == x.value);
            else if (x.key == "!=")
                result = (v != x.value);
                //.....
        });

        return result;
    }))
    <p id="test" condition="return a.location=='sf';"</p>