admin管理员组文章数量:1292141
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.
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.
Share edited Mar 15, 2019 at 23:14 morten.c 3,5155 gold badges42 silver badges47 bronze badges asked Feb 17, 2019 at 7:12 userMod2userMod2 9,00017 gold badges73 silver badges134 bronze badges 8- 3 Inelegant and possibly unsafe. Best to find another way. – CertainPerformance Commented Feb 17, 2019 at 7:14
-
1
You should be able to set up an object
filters
with the functions you need, and then domyJsonData.filter(filters[selectedFilterName])
. That way there can be no code injection. – Thilo Commented Feb 17, 2019 at 7:15 -
1
@CertainPerformance @Thilio - Thanks. So to add more detail, I have a bunch of filter buttons, so each time a new filter button is pressed I may add another condition to the filter in which case I'd need to search the JSON again - e.g.
return (entry.type === 'model' || entry.type === 'photographer' ) && entry.location ==='ny' ;
Any other suggestions to look into then? – userMod2 Commented Feb 17, 2019 at 7:18 - Is there anything stopping you from just dynamically creating the callback with whatever logic you need? – CertainPerformance Commented Feb 17, 2019 at 7:22
- I think "dynamically creating the callback" is roughly the same effort and logic than what you now need to "dynamically create the string to eval", but much safer. – Thilo Commented Feb 17, 2019 at 7:24
3 Answers
Reset to default 8To 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>
You can create an object with the values you want in the output and then filter.
In an if
condition I check whether the advanced filter is applied or not. If applied with check for the &&
condition too. If not, then I will just check the normal condition.
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)
There is nothing wrong in using eval
. Here are three ways you could have done it.
There is of course other ways to do it, but this is a much more dynamic approach.
// 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>
本文标签: jsonJavaScriptUsing eval() for a conditionis it correctStack Overflow
版权声明:本文标题:json - JavaScript - Using eval() for a condition - is it correct? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741549710a2384804.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论