将过滤选项传递给JavaScript过滤方法

3
假设用户想要根据设置以下布尔值来查看音乐家列表:
english_filter = true; // ("EN")
spanish_filter = false; // ("ES")
underground_filter = true; // ("underground")
famous_filter = true; // ("famous")

在上述情况下,用户选择查看会说英语的音乐人,且这些音乐人要么是著名的,要么是地下歌手。
基于这些设置,我想过滤一个名为customArray的数组。
function applyFilters(el) {
   return el.language === "EN" &&  (el.popularity === 'famous' || el.popularity === 'underground');
}

var filtered = customArray.filter(applyFilters);

这是一个传递给applyFilters的“el”结构的示例:
{
id: "sHYNYKFENX"
language: "EN"
name: "John Smith"
popularity: "famous"
profile_image:"https://google.com/fakeimage.jpeg"
recording_handle: "DvYenMhJ8Mo"
recording_title: "Awesome song"
}

上面的代码可以工作,但是我希望能够抽象化它,使用户可以选择任何想要的组合。我该如何创建一个函数来实现这个功能?

非常感谢

更新:

谢谢你们所有人的回答 - 我认为我们已经接近了解决方案。以下是一些预期结果:

var english_filter = false; // ("EN")
var spanish_filter = false; // ("ES")
var underground_filter = false; // ("underground")
var famous_filter = false; // ("famous")

所有音乐家都应该被列出。
var english_filter = false; // ("EN")
var spanish_filter = false; // ("ES")
var underground_filter = true; // ("underground")
var famous_filter = false; // ("famous")

只有地下音乐家,无论他们说什么语言。


如果可能的话,最好制定一种解决方案,可以接受您传递的任何语言,而不仅仅是英语和西班牙语。(不是必需的)。非常感谢大家。你们都很聪明。


可能的组合有哪些? - aneeshep
el 包含什么? - Paul McLoughlin
如果您想返回任何语言,请查看我的答案。您只需不设置filters变量上的“language”属性即可。 - Marcos Dimitrio
3个回答

1
我猜您想使用动态过滤器,比如:
var filters = { language: "EN" };

// or
var filters = { language: "EN", popularity: "famous" };

// or using an array to indicate more than one option
var filters = {
    language: [
        "EN",
        "ES"
    ],
    popularity: "famous"
};

所以,您需要编写一个函数来读取选项并将其与每个对象的属性进行比较:
function applyFilters(elem, filters) {
    var value, name, objectHasThisProperty, propertyHasValue;
    for(name in filters) {
        value = filters[name];

        objectHasThisProperty = elem.hasOwnProperty(name);
        propertyHasValue = isArray(value) ? inArray(elem[name], value) : elem[name] == value;

        if (!objectHasThisProperty || !propertyHasValue) {
            return false;
        }
    }
    return true;
}

然后你会这样调用它:
var filtered = customArray.filter(function(elem) {
    return applyFilters(elem, filters)
});

加上两个辅助函数:

function isArray(variable) {
    return Object.prototype.toString.call(variable) === '[object Array]';
}
function inArray(needle, haystack) {
    return haystack.indexOf(needle) !== -1;
}

在操作中查看:JSFiddle

1
如果您想看会说西班牙语或英语的音乐家,您会如何做? - user1683056

0

怎么样?

var filters = {
  english: { prop:"language", val:"EN", enabled: true},
  spanish: { prop:"language", val:"ES", enabled: false},
  underground: { prop:"popularity", val:"underground", enabled: true},
  famous: { prop:"popularity", val:"famous", enabled: false}
};

function applyFilters(el) {
   for (var i in filters) {
     var f = filters[i];
     if (filters.hasOwnProperty(f) && f.enabled && el[f.prop] !== f.val) return false;
   }
   return true;
}

var filtered = customArray.filter(applyFilters);

而且你可以像这样设置它们

filters.spanish.enabled = true;

你应该使用 filters[f] 而不是 f。而且 underground_filter && famous_filter 应该意味着 el.popularity === 'famous' || el.popularity === 'underground',但你的代码检查的是 el.popularity === 'famous' && el.popularity === 'underground' - Oriol
谢谢你们两位 - @Oriol,你能否请说明一下你的意思? - user1683056
@user1683056 我的意思是,如果同时启用了地下和著名过滤器,根据你的问题,你想要获取那些既著名又地下的物品。但是这段代码将返回既著名又地下的物品,因此不会有任何匹配。 - Oriol
啊,我错过了那个要求。而且被接受的答案基本上是我的变体,所以也不算太糟糕。 - Jan

0

如果我理解正确的话,

function applyFilters(el) {
   return (
     !english_filter && !spanish_filter
     ||
     english_filter && el.language === "EN"
     ||
     spanish_filter && el.language === "ES"
   ) && (
     !underground_filter && !famous_filter
     ||
     underground_filter && el.popularity === 'underground'
     ||
     famous_filter && el.popularity === 'famous'
   );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接