如何根据筛选对象的键与值动态过滤对象数组?
动态筛选订单数组问题
原始数据
订单数组
let filteredOrders = []; // 输出数组 let orders = [ { id: 1, name: "ORDER 1", material: "8756" }, { id: 2, name: "ORDER 2", material: "4548" }, { id: 3, name: "ORDER 3", material: "8756" }, { id: 4, name: "ORDER 4", material: "5678" } ]
筛选条件对象
let filters = { materials: { selected: "" }, ids: { selected: "" } }
筛选需求
- 当筛选条件的
selected值不为空字符串且不为"all"时,需用该条件过滤订单数组 - 支持单个或多个筛选条件同时生效
- 过滤逻辑必须动态实现,禁止硬编码指定订单对象的键名
预期示例
示例1:单一材质筛选
设置筛选条件:
filters.materials.selected = "8756";
预期输出:
filteredOrders = [ { id: 1, name: "ORDER 1", material: "8756" }, { id: 3, name: "ORDER 3", material: "8756" } ]
示例2:多条件组合筛选
设置筛选条件:
filters.materials.selected = "8756"; filters.ids.selected = 3;
预期输出:
filteredOrders = [ { id: 3, name: "ORDER 3", material: "8756" } ]
问题代码及异常现象
尝试了以下代码实现:
for (var [key, value] of Object.entries(filters)) { filteredOrders = orders.filter(function(order) { if (filters[key].selected !== "all" && filters[key].selected !== "") { if (order[key.slice(0, -1)] == filters[key].selected) { console.error("ADD", order, order[key.slice(0, -1)], filters[key].selected); return order; } } }); } // 为空时返回原数组 if (filteredOrders.length < 1) filteredOrders = orders;
异常现象:当同时设置materials.selected="8756"和ids.selected=3时,得到的filteredOrders数组包含3条订单,id为2、3、3(出现重复的id=3数据),不符合预期。
问题分析
- 过滤数据源错误:每次循环都直接基于原始
orders数组过滤,而非上一次的过滤结果,导致最后一次的过滤会覆盖之前的结果,多条件组合逻辑失效 - 闭包变量问题:使用
var声明循环变量key,导致filter回调中访问的key始终是循环的最后一个值 - filter返回值错误:
filter回调需要返回布尔值,而代码中返回order对象(对象在布尔判断中为true,但逻辑上未处理不满足条件的情况)
解决方案
实现思路
- 先收集所有有效的筛选条件:遍历
filters对象,提取selected不为空且不为"all"的条件,同时将筛选键名转换为订单对象对应的属性名(比如materials转为material) - 使用
filter遍历订单数组,每个订单需满足所有有效筛选条件 - 若没有有效筛选条件,直接返回原始订单数组
代码实现
// 收集有效筛选条件 const validFilters = []; for (const [filterKey, filterValue] of Object.entries(filters)) { const { selected } = filterValue; if (selected !== "" && selected !== "all") { // 将筛选键名转为订单对象的属性名(去掉末尾的s) const orderKey = filterKey.slice(0, -1); validFilters.push({ key: orderKey, value: selected }); } } // 执行过滤:若没有有效条件则返回原数组,否则检查每个订单是否满足所有条件 filteredOrders = validFilters.length === 0 ? [...orders] : orders.filter(order => { return validFilters.every(({ key, value }) => { // 注意类型匹配,这里用==兼容字符串和数字的情况,若需要严格匹配可改为=== return order[key] == value; }); });
测试验证
- 单条件筛选(
materials.selected="8756"):返回id=1、3的订单,符合预期 - 多条件筛选(
materials.selected="8756"+ids.selected=3):仅返回id=3的订单,符合预期 - 无有效条件(所有selected为空或"all"):返回原始订单数组
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

