专栏名称: 众成翻译
翻译,求知的另一种表达
目录
相关文章推荐
西藏发布  ·  2025年西藏林芝桃花节“大剧透” ·  10 小时前  
西藏发布  ·  2025年西藏林芝桃花节“大剧透” ·  10 小时前  
TGB湖南人  ·  【2.25复盘】下跌是为了更好的上涨!有些股 ... ·  15 小时前  
西藏发布  ·  西藏一机场最新消息! ·  20 小时前  
西藏发布  ·  西藏一机场最新消息! ·  20 小时前  
西藏生态环境保护  ·  学辐射环评知识 ... ·  2 天前  
西藏生态环境保护  ·  学辐射环评知识 ... ·  2 天前  
51好读  ›  专栏  ›  众成翻译

JavaScript .filter() 方法全解析

众成翻译  · 掘金  ·  · 2018-08-29 10:13

正文

.filter是一个内置的数组迭代方法,它接受一个“谓词(译者注: 指代一个过滤条件的函数)”,该“谓词”针对每个值进行调用,并返回一个符合该条件(“truthy值”)的数组。

上面那句话包含了很多信息,让我们来逐一解答一下。

  • “内置”只是意味着它是语言的一部分 - 您不需要添加任何库来访问此功能。

  • “迭代方法”是指接受针对数组的每个项运行的函数。.map和.reduce都是迭代方法的示例。

  • “谓词”是指.fiflter中接受的的函数。

  • “truthy值”是强制转换为布尔值时计算为true的任何值。几乎所有值都是真实的,除了:undefined,null,false,0,NaN或“”(空字符串)。

让我们来看看下面这个例子,看一下.filter是怎么运行的。

const restaurants = [
    {
        name: "Dan's Hamburgers",
        price: 'Cheap',
        cuisine: 'Burger',
    },
    {
        name: "Austin's Pizza",
        price: 'Cheap',
        cuisine: 'Pizza',
    },
    {
        name: "Via 313",
        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: 'Moderate',
        cuisine: 'Burger',
    },
    {
        name: "Chuy's",
        cuisine: 'Tex-Mex',
        price: 'Moderate',
    },
    {
        name: "Taquerias Arandina",
        cuisine: 'Tex-Mex',
        price: 'Cheap',
    },
    {
        name: "El Alma",
        cuisine: 'Tex-Mex',
        price: 'Expensive',
    },
    {
        name: "Maudie's",
        cuisine: 'Tex-Mex',
        price: 'Moderate',
    },
];

这是很多信息。我现在想要一个汉堡,所以让我们过滤掉一下这个数组。

const isBurger = ({cuisine}) => cuisine === 'Burger';
const burgerJoints = restaurants.filter(isBurger);

isBurger是谓词,而burgerJoints是 new 数组,它是餐馆的子集。 值得注意的是,restaurants 这个数组是不变。

下面是两个正在呈现的列表的简单示例 - 一个原始的餐馆数组,以及一个过滤的burgerJoints数组。

See the Pen .filter - isBurger by Adam Giese ( @AdamGiese ) on CodePen .

否定谓词

对于每个谓词,都有一个相反的否定谓词。

谓词是一个返回布尔值的函数。由于布尔值只有true 和 false,这意味着很容易“翻转”谓词的值。

我吃了汉堡已经过了几个小时,现在又饿了。这一次,我想过滤 out 汉堡尝试新的东西。一种选择是从头开始编写新的isNotBurger谓词。

const isBurger = ({cuisine}) => cuisine === 'Burger';
const isNotBurger = ({cuisine}) => cuisine !== 'Burger';

但是,请查看两个谓词之间的相似程度。这不是 DRY code 。另一种选择是调用isBurger谓词并翻转结果。

const isBurger = ({cuisine}) => cuisine === 'Burger';
const isNotBurger = restaurant => !isBurger(restaurant);

这个更好!如果汉堡的定义发生变化,您只需要在一个地方更改逻辑。但是,如果我们想要一些否定的谓词呢?由于这是我们可能经常想要做的事情,因此编写否定函数可能是个好主意。

const negate = predicate => function() {
  return !predicate.apply(null, arguments);
}

const isBurger = ({cuisine}) => cuisine === 'Burger';
const isNotBurger = negate(isBurger);

const isPizza = ({cuisine}) => cuisine === 'Pizza';
const isNotPizza = negate(isPizza);

你可能有一些问题。

什么是.apply?

MDN:

apply()方法调用具有给定this的函数,并将参数作为数组(或类数组对象)提供。

什么是arguments?

MDN:

arguments对象是所有(非箭头)函数中可用的局部变量。您可以使用参数在函数内引用函数的参数object.

为什么要使用旧的function,而不使用更酷的箭头函数?

在这种情况下,使用传统函数是必要的,因为arguments对象在传统函数上是_唯一_可用的。

到2018年8月20日。 正如一些评论家所正确指出的那样, 你可以使用 rest参数 箭头函数写\ negate \

返回谓词

正如我们在使用negate函数看到的那样,函数很容易在JavaScript中返回一个新函数。这对于编写“谓词”非常有用。例如,让我们回顾一下我们的isBurger和isPizza谓词。

const isBurger = ({cuisine}) => cuisine === 'Burger';
const isPizza  = ({cuisine}) => cuisine === 'Pizza';

这两个谓词具有相同的逻辑;他们只是在比较上有所不同。因此,我们可以将共享逻辑包装在isCuisine函数中。

const isCuisine = comparison => ({cuisine}) => cuisine === comparison;
const isBurger  = isCuisine('Burger');
const isPizza   = isCuisine('Pizza');

现在,如果我们想开始检查价格怎么办?

const isPrice = comparison => ({price}) => price === comparison;
const isCheap = isPrice('Cheap');
const isExpensive = isPrice('Expensive');

现在isCheap和isExpensive 都是DRY(译者注:Don't repeat yourself ,一种编程原则,不也要写重复的代码),isPizza和isBurger都是DRY,但isPrice和isCuisine可以公用他们的逻辑!

const isKeyEqualToValue = key => value => object => object[key] === value;

// these can be rewritten
const isCuisine = isKeyEqualToValue('cuisine');
const isPrice = isKeyEqualToValue('price');

// these don't need to change
const isBurger = isCuisine('Burger');
const isPizza = isCuisine('Pizza');
const isCheap = isPrice('Cheap');
const isExpensive = isPrice('Expensive');

对我来说,这就是箭头功能之美。在一行中,您可以优雅地创建三阶函数。

看看从原始餐馆阵列创建多个筛选列表是多么容易?

See the Pen .filter - returning predicates by Adam Giese ( @AdamGiese ) on CodePen .

撰写谓词

我们现在可以通过汉堡或廉价的价格过滤我们的阵列......但是如果你想要 cheap burgers 怎么办?一种选择是将两个过滤器链接在一起。

const cheapBurgers = restaurants.filter(isCheap).filter(isBurger);

另一个选择是将两个谓词“组合”成一个谓词。

const isCheapBurger = restaurant => isCheap(restaurant) && isBurger(restaurant);
const isCheapPizza = restaurant => isCheap(restaurant) && isPizza(restaurant);

看看所有重复的代码。我们绝对可以将它包装成一个新功能!







请到「今天看啥」查看全文