基于对象函数实现动态筛选器的技术方案问询
问题
开发类似Yahoo Screener的动态筛选器,已定义FilterField接口及fields数组,希望通过每个字段的f函数实现数据筛选,但f函数无法读取自身字段的inclusion、lastValue等属性(以dayOfWeek字段为例),需解决这一问题。
相关代码定义:
export interface FilterField { label: string; selected: boolean; deletable: boolean; required?: boolean; lastValue?: any; viewSync?: boolean; inclusion?: 'include' | 'exclude'; precision?: 'before' | 'after' | 'exact'; controlType?: 'multiselect' | 'time' | 'tag'; items?: Array<unknown>; f?: Function; }
public fields: Array<FilterField> = [ { label: 'period', viewSync: true, selected: true, deletable: false, lastValue: null, required: true, f: (data: SomeObject) => { // 筛选函数逻辑 } }, { label: 'dayOfWeek', inclusion: 'include', selected: true, deletable: true, lastValue: [1,2], f: (data: SomeObject) => { // 无法获取当前字段的inclusion和lastValue return inclusion == 'include' ? lastValue.includes(moment(data.date).startOf('day').day()) : !lastValue.includes(moment(data.date).startOf('day').day()) } }, { /* 其他字段 */ } ]
解决方案
方法1:修改f函数签名,传入当前字段
直接调整FilterField接口中f的类型,让它接收当前字段作为第二个参数,调用筛选逻辑时将字段自身传递进去即可访问属性。
步骤:
- 更新
FilterField接口的f定义:
export interface FilterField { // ... 其他属性不变 f?: (data: SomeObject, field: FilterField) => boolean; }
- 修改
dayOfWeek字段的f函数,通过第二个参数访问字段属性:
{ label: 'dayOfWeek', inclusion: 'include', selected: true, deletable: true, lastValue: [1,2], f: (data: SomeObject, field: FilterField) => { // 用可选链处理属性可能为undefined的情况 const inclusion = field.inclusion ?? 'include'; const lastValue = field.lastValue ?? []; const day = moment(data.date).startOf('day').day(); return inclusion === 'include' ? lastValue.includes(day) : !lastValue.includes(day); } }
- 在执行筛选的逻辑中,调用
f时传入当前字段:
// 假设dataList是待筛选的数据数组 const filteredData = dataList.filter(item => { return fields.every(field => { // 只处理选中且有筛选函数的字段 if (!field.selected || !field.f) return true; return field.f(item, field); }); });
方法2:利用闭包绑定当前字段
定义字段时先用变量保存字段引用,让f函数通过闭包捕获这个变量,从而直接访问字段属性,无需修改接口定义。
示例:
// 单独定义dayOfWeek字段,用变量保存引用 const dayOfWeekField: FilterField = { label: 'dayOfWeek', inclusion: 'include', selected: true, deletable: true, lastValue: [1,2], f: (data: SomeObject) => { const inclusion = dayOfWeekField.inclusion ?? 'include'; const lastValue = dayOfWeekField.lastValue ?? []; const day = moment(data.date).startOf('day').day(); return inclusion === 'include' ? lastValue.includes(day) : !lastValue.includes(day); } }; // 将变量加入fields数组 public fields: Array<FilterField> = [ { /* period字段 */ }, dayOfWeekField, { /* 其他字段 */ } ];
后续修改字段属性(比如lastValue)时,闭包会自动获取最新值,因为它引用的是变量本身。
方法3:绑定this指向当前字段(类环境适用)
如果fields是类的成员变量,可在构造函数中重新绑定每个字段f函数的this指向当前字段,但需注意f必须是普通函数(箭头函数的this无法被修改)。
步骤:
- 修改
dayOfWeek字段的f为普通函数:
{ label: 'dayOfWeek', inclusion: 'include', selected: true, deletable: true, lastValue: [1,2], f: function(data: SomeObject) { const inclusion = this.inclusion ?? 'include'; const lastValue = this.lastValue ?? []; const day = moment(data.date).startOf('day').day(); return inclusion === 'include' ? lastValue.includes(day) : !lastValue.includes(day); } }
- 在类的构造函数中绑定
this:
constructor() { this.fields.forEach(field => { if (field.f) { // 将f函数的this绑定到当前字段 field.f = field.f.bind(field); } }); }
内容的提问来源于stack exchange,提问作者pop
相关产品推荐
相关产品推荐

