当我在下面详细介绍我的用例(希望不要太多)时,请记住基本问题是“如何在运行时在 javascript 中创建自定义函数?”
我有(可能很大)对象数组,用户可以在这些对象上构建自定义搜索。搜索函数会传递一个格式为
的过滤器数组[{field:'name', predicate:'contains', modifier:'Joe'},
{field:'type', predicate:'is', modifier:'Boss'}]
在此示例中将返回所有名为 Joe 的 Boss。
为此,我创建了一个过滤函数,将过滤器应用于主列表,如下所示:
var matches = everythingOfThatType;
whereClause.forEach(function(filter) {
switch(filter.predicate) {
case '=':
case 'is':
matches = matches.filter(function(record) { return record[filter.field] == filter.modifier; });
console.log(filter, matches);
break;
case '!=':
case 'is not':
matches = matches.filter(function(record) { return record[filter.field] != filter.modifier; });
console.log(filter, matches);
break;
...
等等。
它工作正常,但现在我遇到了一些粗糙的复杂性(过滤器组合的特殊规则,数组属性的递归过滤等),并且为了性能,最好只迭代所有候选者的列表无论如何,一次。
我理想的解决方案看起来像这样
var filterFunc = magicallyCreateFilterFunc(filters);
var matches = everythingOfThatType.filter(filterFunc);
其中 magicallyCreateFilterFunc()
将具有类似于原始 switch 语句的内容,但不是应用过滤器,而是向函数添加一行,该函数最终将应用于所有对象。然后我可以以紧凑、高效的方式添加所有其他复杂性和递归等。
在我看来,JavaScript 非常适合此类任务(顺便说一句,我对 JavaScript 的了解越深入,我就越欣赏它的深度),但我在第 1 步上有点卡住了:动态定义基于运行时数据的函数。我真的很感激能朝正确的方向插入。
最佳答案
事实证明有一种简单、干净的方法可以做到这一点。当我问这个问题时我不知道哦,很久以前,闭包和过滤器是最好的 friend 。
我可以将过滤器函数添加到数组中,然后使用闭包在数组的每个成员上执行所有函数,而不是在 switch 语句中应用过滤器。
所以我上面的 switch 语句看起来更像
var buildFilterList = function(whereClause) {
var filterFunctions = [];
whereClause.forEach(function(filter) {
switch(filter.predicate) {
case '=':
case 'is':
filterFunctions.push((function(field) { return function(record) { return record[filter.field] == filter.modifier; })})(field));
break;
...
这给了我一个应用于每个元素的函数列表,每个元素都在一个包含它应该应用于的字段的闭包中。更复杂的过滤函数可能有更多的参数。现在,如何有效地获取过滤器列表并应用它们?再次关闭。
var filterApplicator = function(filters) {
return function(item) {
var passed = true, i = 0, filterCount = filters.length;
for (i = 0; passed && i < filterCount; i++) {
passed = filters[i](item);
}
return passed;
}
}
var filterFunctions = buildFilterList(whereClause);
matches = everythingOfThatType.filter(filterApplicator(filterFunctions));
filterApplicator()
返回一个将应用于原始数组中每个元素的函数。该函数位于包含过滤器函数数组的闭包中,因此它所要做的就是循环这些函数并将它们应用于元素,直到失败为止。
(需要注意的是,我还没有测试过这个确切的语法,但基本概念是我想在这里传递的。)
关于javascript在运行时构建过滤器函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21788907/