我有使用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 ;
});
这就是为什么我制作了一个单独的类来创建该字符串的原因。
答案 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>