.filter是一种内置的数组迭代方法,它接受一个“谓词”,该谓词根据调用的每个值进行评估,并返回一个与该条件匹配的数组(“真值”)。上面那句话包含了很多信息,我们一一解答。“内置”只是意味着它是语言的一部分——你不需要添加任何库来访问这个功能。“迭代方法”是指接受在数组的每个项目上运行的函数。.map和.reduce都是迭代方法的例子。“Predicate”是指.fifilter中接受的函数。“真值”是在强制转换为布尔值时计算结果为真的任何值。几乎所有值都是true,除了:undefined、null、false、0、NaN或""(空字符串)。让我们看看下面的例子,看看.filter是如何工作的。constrestaurants=[{name:"Dan'sHamburgers",price:'Cheap',cuisine:'Burger',},{name:"Austin'sPizza",price:'Cheap',cuisine:'Pizza',},{名称:"Via313",price:'Moderate',cuisine:'Pizza',},{name:"Bufalina",price:'Expensive',cuisine:'Pizza',},{name:"P.Terry's",}price:'Cheap',cuisine:'Burger',},{name:"Hopdoddy",price:'Expensive',cuisine:'Burger',},{name:"Whataburger",price:'适中',cuisine:'Burger',},{name:"Chuy's",cuisine:'Tex-Mex',price:'Moderate',},{name:"TaqueriasArandina",cuisine:'Tex-Mex',price:'便宜',},{name:"ElAlma",cuisine:'Tex-Mex',price:'昂贵',},{name:"Maudie's",cuisine:'Tex-Mex',price:'Moderate',},];这是我现在想要一个汉堡的大量信息,所以让我们过滤掉该数组。constisBurger=({cuisine})=>cuisine==='Burger';constburgerJoints=restaurants.filter(isBurger);isBurger是谓词,而burgerJoints是新数组,它是餐厅的子集。值得注意的是restaurants数组没有改变。下面是一个呈现两个列表的简单示例-原始餐厅数组和经过过滤的burgerJoints数组。请参阅CodePen上AdamGiese(@AdamGiese)的Pen.filter-isBurger。否定谓词对于每个谓词,都有一个相反的否定谓词。谓词是返回布尔值的函数。由于布尔值只有true和false,这意味着很容易“翻转”谓词的值。我已经好几个小时没吃汉堡了,我又饿了。这一次,我想过滤掉汉堡来尝试新的东西。一种选择是从头开始编写一个新的isNotBurger谓词。constisBurger=({cuisine})=>cuisine==='Burger';constisNotBurger=({cuisine})=>cuisine!=='Burger';但是,看看这两个谓词有多相似。这不是DRY代码。另一种选择是调用isBurger谓词并翻转结果。constisBurger=({cuisine})=>cuisine==='Burger';constisNotBurger=restaurant=>!isBurger(餐厅);这个更好!如果汉堡包的定义改变了,你只需要改变一个地方的逻辑。但是如果我们想要一些否定谓词怎么办?由于这是我们可能想要经常做的事情,因此编写一个否定函数可能是个好主意。constnegate=predicate=>function(){return!predicate.apply(null,arguments);}constisBurger=({cuisine})=>cuisine==='汉堡';constisNotBurger=否定(isBurger);constisPizza=({cuisine})=>cuisine==='披萨';constisNotPizza=否定(isPizza);你可能有一些问题。.apply是什么?MDN:apply()方法使用给定的this调用函数,并将参数作为数组(或类数组对象)提供。什么是论据?MDN:arguments对象是所有(非箭头)函数中可用的局部变量。您可以使用参数在函数内引用函数的参数对象。为什么使用旧函数而不是更酷的箭头函数?在这种情况下,使用传统函数是必要的,因为参数对象_仅_在传统函数上可用。直到2018年8月20日。正如一些评论员正确指出的那样,您可以使用剩余参数来编写带有[arrowfunctions](https://css-tricks.com/level-....returnpredicatesaswesawwithnegatefunctions这样,在JavaScript中一个函数很容易返回一个新的函数。这对于编写“谓词”非常有用。例如,让我们回顾一下我们的isBurger和isPizza谓词。constisBurger=({cuisine})=>cuisine==='Burger';constisPizza=({cuisine})=>cuisine==='Pizza';这两个谓词的逻辑是一样的,只是对比不同而已,所以我们可以把共享的逻辑包裹在isCuisine中功能中间。constisCuisine=comparison=>({cuisine})=>cuisine===比较;constisBurger=isCuisine('Burger');constisPizza=isCuisine('披萨');现在,如果我们想开始检查价格怎么办?constisPrice=comparison=>({price})=>price===comparison;constisCheap=isPrice('便宜');constisExpensive=isPrice('昂贵');现在isCheap和isExpensive都是DRY(译者注:不要重复自己,一个编程原则,不要写重复的代码),isPizza和isBurger都是DRY,但是isPrice和isCuisine可以共享它们的逻辑!constisKeyEqualToValue=key=>value=>object=>object[key]===value;//这些可以重写constisCuisine=isKeyEqualToValue('cuisine');constisPrice=isKeyEqualToValue('price');//这些不用改constisBurger=isCuisine('Burger');constisPizza=isCuisine('披萨');constisCheap=isPrice('便宜');constisExpensive=isPrice('昂贵');这就是箭头函数的美妙之处。在一行中,您可以优雅地创建三阶函数。看看从原始餐厅数组创建多个筛选列表是多么容易?请参阅CodePen上AdamGiese(@AdamGiese)的Pen.filter-返回谓词。编写谓词我们现在可以按汉堡或便宜的价格过滤我们的数组......但是如果你想要便宜的汉堡怎么办?一种选择是将两个过滤器链接在一起。constcheapBurgers=restaurants.filter(isCheap).filter(isBurger);另一种选择是将两个谓词“组合”成一个谓词。constisCheapBurger=restaurant=>isCheap(餐厅)&&isBurger(餐厅);constisCheapPizza=restaurant=>isCheap(餐厅)&&isPizza(餐厅);查看所有重复的代码。我们绝对可以将其包装成一个新功能!constboth=(predicate1,predicate2)=>value=>predicate1(value)&&predicate2(value);constisCheapBurger=both(isCheap,isBurger);constisCheapPizza=both(isCheap,isPizza);constcheapBurgers=restaurants.filter(isCheapBurger);constcheapPizza=restaurants.filter(isCheapPizza);如果你没有比萨饼或汉堡包怎么办?consteither=(predicate1,predicate2)=>value=>predicate1(value)||谓词2(值);constisDelicious=either(isBurger,isPizza);constdeliciousFood=restaurants.filter(isDelicious);这是朝着正确方向迈出的一步,但是如果你想包括两种以上的食物怎么办?这不是一种可扩展的方法。有两个内置的数组方法在这里派上用场。.every和.some都是谓词方法,也接受谓词。.every检查数组的每个成员是否通过谓词,.some检查数组的任何成员是否通过谓词。constisDelicious=restaurant=>[isPizza,isBurger,isBbq].some(predicate=>predicate(restaurant));constisCheapAndDelicious=restaurant=>[isDelicious,isCheap].every(predicate=>predicate(restaurant));和往常一样,让我们??将它们包装成一些有用的抽象。constisEvery=predicates=>value=>predicates.every(predicate=>predicate(value));constisAny=predicates=>value=>predicates.some(predicate=>predicate(value));constisDelicious=isAny([isBurger,isPizza,isBbq]);constisCheapAndDelicious=isEvery([isCheap,isDelicious]);isEvery和isAny都接受一个谓词数组并返回一个谓词。由于所有这些谓词都可以通过高阶函数轻松创建,因此基于用户交互创建和应用这些谓词并不困难。将我们学到的所有课程放在一起,这是一个示例应用程序,它通过应用基于按钮点击的过滤器来搜索餐馆。请参阅CodePen上AdamGiese(@AdamGiese)的Pen.filter-动态过滤器。总结过滤器是JavaScript开发的重要组成部分。无论您是从API响应中挑选出错误数据还是响应用户交互,您都会无数次需要数组值的子集。我希望这个概述可以帮助您操作谓词以编写更具可读性和可维护性的代码。
