JavaScript – Using eval() for a condition – is it correct?

  • A+

I have JSON data that I am searching through using filter:

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

Now instead of specifying those conditions after return, I've created a similar string (because I want to have a list of pre-created search conditions) then using eval() so:

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

This appears to work. However, I just want to confirm, is this its correct usage? Are there any risks/issues in doing this?

I want to have the flexibility to do, any kind of search e.g.:

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

That's why I made a separate class to create that string.


To avoid eval you could translate user input (through buttons, or whatever) to filters. Those filters would have one filter per data property (i.e. per location, type, level, ...). One of those filters could either be a list of values, or a free-text single value.

Here is an example implementation with a sample data set, without any sexy input/output widgets,... just the bare minimum to demo the algorithm of filtering:

// 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>


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: