热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JavaScript.filter()要领全剖析

.filter是一个内置的数组迭代要领,它接收一个“谓词(译者注:指代一个过滤前提的函数)”,该“谓词”针对每一个值举行挪用,并返回一个相符该前提(“truthy值”)的数组。上面

.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 ](https://css-tricks.com/level-…。

返回谓词

正如我们在运用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);

看看一切反复的代码。我们相对能够将它包装成一个新功用!

const both = (predicate1, predicate2) => value =>
predicate1(value) && predicate2(value);
const isCheapBurger = both(isCheap, isBurger);
const isCheapPizza = both(isCheap, isPizza);
const cheapBurgers = restaurants.filter(isCheapBurger);
const cheapPizza = restaurants.filter(isCheapPizza);

假如你没有披萨或汉堡包怎样办?

const either = (predicate1, predicate2) => value =>
predicate1(value) || predicate2(value);
const isDelicious = either(isBurger, isPizza);
const deliciousFood = restaurants.filter(isDelicious);

这是朝着准确方向迈出的一步,然则假如您想要包括两种以上的食品呢?这不是一种可扩大的要领。有两种内置的数组要领在这里派上用场。.every和.some都是谓词要领,也接收谓词。.every搜检数组的每一个成员是不是通报谓词,而.some搜检数组的any成员是不是经由过程谓词。

const isDelicious = restaurant =>
[isPizza, isBurger, isBbq].some(predicate => predicate(restaurant));
const isCheapAndDelicious = restaurant =>
[isDelicious, isCheap].every(predicate => predicate(restaurant));

而且,像平常一样,让我们​​将它们包装成一些有效的笼统。

const isEvery = predicates => value =>
predicates.every(predicate => predicate(value));
const isAny = predicates => value =>
predicates.some(predicate => predicate(value));
const isDelicious = isAny([isBurger, isPizza, isBbq]);
const isCheapAndDelicious = isEvery([isCheap, isDelicious]);

isEvery和isAny都接收一个谓词数组并返回一个谓词。

由于一切这些谓词都能够经由过程高阶函数轻松建立,因而依据用户的交互建立和运用这些谓词并不难题。综合我们学到的一切课程,这里是一个运用程序示例,经由过程运用基于按钮点击的过滤器来搜刮餐馆。

See the Pen .filter – dynamic filters by Adam Giese (@AdamGiese) on CodePen.

总结
过滤器是Javascript开辟的主要组成部分。不管您是从API相应中挑选出毛病数据照样响运用户交互,您都邑无数次想要数组值的子集。我愿望这个概述有助于您能够操纵谓词来编写更易读和可保护的代码。


推荐阅读
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • express工程中的json调用方法
    本文介绍了在express工程中如何调用json数据,包括建立app.js文件、创建数据接口以及获取全部数据和typeid为1的数据的方法。 ... [详细]
  • 本文介绍了如何在Jquery中通过元素的样式值获取元素,并将其赋值给一个变量。提供了5种解决方案供参考。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 热血合击脚本辅助工具及随机数生成器源码分享
    本文分享了一个热血合击脚本辅助工具及随机数生成器源码。游戏脚本能够实现类似真实玩家的操作,但信息量有限且操作不可控。热血合击脚本辅助工具可以帮助玩家自动刷图、换图拉怪等操作,并提供了雷电云手机的扩展服务。此外,还介绍了使用mt_rand函数作为随机数生成器的代码示例。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 用Vue实现的Demo商品管理效果图及实现代码
    本文介绍了一个使用Vue实现的Demo商品管理的效果图及实现代码。 ... [详细]
author-avatar
信雨2502873867
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有