关于阮一峰老师es6(第三版)中管道机制代码的理解浅析
最近正在学习阮一峰老师的es6(第三版)教材,在学到第七章《函数的扩展》中的箭头函数嵌套时,文中提到了一个关于“管道机制”的示例,文中源代码如下:
//es6(第三版)教材中的管道机制源代码:
const pipeline = (...funcs) =>
val => funcs.reduce((a, b) => b(a), val);
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);
addThenMult(5);
下面为我对这段代码的理解分析:
一、这段代码中用到了2个主要知识点:
1、es6中的新特性:rest参数(即上面代码中pipeline函数的形参…funcs,它表示pipeline函数的形参是一个包含多个函数的函数数组,funcs则为数组名),形式为:…变量名。用于获取函数的多个参数,类似于之前的arguments对象。rest参数搭配的变量是一个数组,该变量可以将多个参数放入其中。因为rest参数中的变量代表一个数组,所以数组特有的方法都可以用于这个变量。
2、数组对象的reduce()方法(这也是实现管道机制的核心技术):
reduce() 方法接收一个函数作为回调函数,reduce()方法为数组中的每一个元素(从左到右)依次执行这个回调函数,最终计算为一个值。
语法:arrayObject.reduce(function(prev, currentItem, currentIndex, arrayObject), initialValue)
参数:
●prev:必需。表示数组中前一个元素调用reduce() 方法回调函数后的返回值,或者初始值 initialValue;
●currentItem:必需。表示当前正在调用reduce() 方法回调函数的数组元素;
●currentIndex:可选。表示当前正在调用reduce() 方法回调函数的数组元素的索引。若提供了 initialValue值,则索引为0,否则索引为1;
●arrayObject:可选。当前正在调用reduce() 方法回调函数元素所属的数组对象(即调用reduce()的数组);
●initialValue:可选。传递给此reduce() 方法回调函数的初始值。作为第一次调用回调函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
关于initialValue参数作用的进一步说明:回调函数第一次执行时,prev 和currentItem的取值有两种情况:如果调用reduce()时提供了initialValue,则prev取值为initialValue,currentItem取数组中的第一个元素;如果没有提供 initialValue,那么prev取数组中的第一个元素,currentItem取数组中的第二个元素。如果没有提供initialValue,reduce 会从索引1的数组元素开始执行回调函数,跳过第0个索引。如果提供initialValue,则从索引0开始。如果数组为空且没有提供initialValue,会抛出TypeError 。如果数组仅有一个元素,并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且回调函数不会被执行。
关于reduce()方法的运用实例,可以参照MDN这篇文章:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce,会更有利于帮助理解这个方法的用途。以下为MDN部分截图:
二、管道机制(pipeline):(MDN中也称“功能型函数管道”)即前一个函数的输出是后一个函数的输入。管道机制类似于jQuery中的链式编程,以return的形式持续操作。
三、这段代码实现的功能为:让一个数字先与1相加,得出的结果然后再与2相乘,最后返回计算后的结果。
四、经过对上面代码的一番思考,我根据自己的理解将上面代码的参数表示稍作了一点语义化的改动,让我更清晰的理解这段代码的运行机制:
const pipeline = (...funcs) =>
num => {
console.log( num);
return funcs.reduce((prev, fn) => fn(prev), num);
}
const plus1 = num=> num + 1;
const mult2 = lastresult => lastresult * 2;
const addThenMult = pipeline(plus1, mult2);
console.log(addThenMult(5)) ; //12
下面为这段代码的具体注释详解:
const pipeline = (...funcs) =>
num => {
//打印这个形参 num看一下, num就是传递给reduce方法里回调函数的初始值
console.log( num);
//funcs数组调用reduce()方法,这时,初始值num就是reduce回调函数中的第一个形参prev,而此时reduce回调函数中的第二个形参fn则代表funcs数组里的第一个函数。根据这个回调函数的函数体:(prev, fn) => fn(prev)执行,首先将初始值num(即prev)传递给funcs数组里的第一个函数(即fn())作为实参并进行第一个函数的调用,第一个函数的运算结果(即lastresult)得出后紧接着把这个结果再传给funcs数组里第二个函数作为第二个函数的实参并进行调用,第二个函数的运算结果得出后紧接着再传给第三个函数作为第三个函数的实参并进行调用,以此类推。。。。。。直到funcs数组中的最后一个函数元素执行完毕后,pipeline函数返回的函数的返回值就是reduce()方法的返回值,而reduce()方法的返回值就是funcs数组中最后一个函数参数执行回调函数后返回的值。
return funcs.reduce((prev, fn) => fn(prev), num);
}
const plus1 = num => num + 1;
const mult2 = lastresult => lastresult * 2;
//实参plus1函数对应形参funcs数组中的第一项元素,也就是pipeline函数的第一个形参
//实参mult2函数对应形参funcs数组中的第二项元素,也就是pipeline函数的第二个形参
const addThenMult = pipeline(plus1, mult2);
//这里的实参“5”就是传递给pipeline()函数return回的addThenMult函数中funcs数组调用reduce()方法后的回调函数的初始值 num。 5会先作为plus1函数的实参传入并执行plus1函数,结果为5+1=6;然后再将这个结果6(即lastresult)传递给mult2函数作为mult2函数的实参并执行mult2函数,结果为6*2=12。
console.log(addThenMult(5))
//所以最后devtools中上面两处console.log()打印出的结果分别为:
>>5
>>12
五、最后,再附上一张MDN中对于管道机制的一个示例,也可以帮助更好的理解管道机制的实现原理:
关于阮一峰老师es6(第三版)中管道机制代码的理解浅析的更多相关文章
- 读阮一峰老师 es6 入门笔记 —— 第一章
鉴于最近用 vuejs 框架开发项目,其中有很多涉及到 es6 语法不太理解所以便认真地读了一下这本书. 地址:http://es6.ruanyifeng.com/#README 第一章:let ,c ...
- 【js 笔记】读阮一峰老师 es6 入门笔记 —— 第一章
鉴于最近用 vuejs 框架开发项目,其中有很多涉及到 es6 语法不太理解所以便认真地读了一下这本书. 地址:http://es6.ruanyifeng.com/#README 第一章:let ...
- 【js 笔记】读阮一峰老师 es6 入门笔记 —— 第二章
第二章:变量的解构赋值 在es6 版本前,如果要为多个变量赋不同值,我想是件比较麻烦的事情.但es6 版本新推出了一个新技术那就是今天的主角变量的解构赋值. 变量解构赋值分为两种方法:数组解构赋值 和 ...
- ES6特性:(阮一峰老师)学习总结
ES6(阮一峰)学习总结 1.块级作用域的引入 在ES6之前,js只有全局作用域和函数作用域,ES6中let关键字为其引入了块级作用域. { var a = 5; let b = 6; } con ...
- react 入门教程 阮一峰老师真的是榜样
- 转自阮一峰老师博客 React 入门实例教程 作者: 阮一峰 日期: 2015年3月31日 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Nati ...
- 监控阮一峰老师的blog
引言 阮一峰大家基本都认识,很厉害的一个人,经济学博士,文章写得很棒,知识面很广泛,计算机.算法.英语.文采,这是能想到的他的一些标签,他的博客应该算是最受欢迎的博客之一了. 我经常回去看他的博客,但 ...
- 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题
调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...
- Unix环境高级编程第三版中实例代码如何在自己的linux上运行的问题
学习Linux已经有2个月了,最近被期末考试把进度耽误了,前几天把Unix环境高级编程看了两章,感觉对Linux的整体有了一些思路,今天尝试着对第一章涉及到的一个简单的交互式shell编译运行一下,结 ...
- scss初学小结(转阮一峰老师SASS用法指南http://www.ruanyifeng.com/blog/2012/06/sass.html)
1.安装 SASS是Ruby语言写的,但是两者的语法没有关系.不懂Ruby,照样使用.只是必须先安装Ruby,然后再安装SASS. 假定你已经安装好了Ruby,接着在命令行输入下面的命令: gem i ...
随机推荐
- dnspy使用技巧
打开dnspy,调试–>附加到进程–>选择相应的进程ID–>附加(支持同时附加多个进程) 调试–>窗口–>模块–>搜索要调试的程序集–>双击(这一步很重要, ...
- 转载: beta分布介绍
最近在看机器学习方面的资料,作为入门的李航教授所写的<统计机器学习>一书,刚看完第一章我也是基本处于懵了的状态,其中有一道题提到贝叶斯估计,看了下网上的资料都提到了一个叫做 beta分布的 ...
- Jmeter启动闪退
背景:使用Jmeter进行性能测试脚本开发,实现Jmeter接口开发Java请求 问题再现: 1.在官网上下载Jmeter3.2版本,打开jmeter.bat,启动成功 2.在IDEA中创建测试项目和 ...
- MapReduce编程实例
MapReduce常见编程实例集锦. WordCount单词统计 数据去重 倒排索引 1. WordCount单词统计 (1) 输入输出 输入数据: file1.csv内容 hellod world ...
- iOS——归档对象的创建,数据写入与读取
归档(archiving)是指另一种形式的序列化,但它是任何对象都可以实现的更常规的模型.专门编写用于保存数据的任何模型对象都应该支持归档.比属性列表多了很良好的伸缩性,因为无论添加多少对象,将这些对 ...
- Python3 Selenium自动化web测试 ==>FAQ:PyCharm中脚本不执行main函数内容解决方案
FAQ: 情景:之前写好可以正常执行的python脚本,突然main函数下的代码不运行 原因:pycharm中,会设置py脚本按照unittest的方式运行,也就是只运行用例,不运行main函数下代码 ...
- 阿里云Centos 7.6安装Redis以及开启远程连接
下载地址:http://redis.io/download,下载最新稳定版本. 本教程使用的最新文档版本为 5.0.5,下载并安装: $ wget http://download.redis.io/r ...
- 除了 UCAN 发布的鹿班和普惠体,这些设计工具也来自阿里
在 4 月 27 日的 UCAN 2019 设计大会上,阿里巴巴对外发布了一款全新免费字体——阿里巴巴普惠体.其实,作为经济体的阿里巴巴,这些年早已默默推出了很多实用的设计工具,比如大名鼎鼎的 Ico ...
- 【ARM-LInux开发】如何运行wayland
Running Wayland 原文:https://jan.newmarch.name/Wayland/RunningWayland/ skip table of contents Show tab ...
- 【DSP开发】帮您快速入门 TI 的 Codec Engine
德州仪器半导体技术(上海)有限公司 通用DSP 技术应用工程师 崔晶 德州仪器(TI)的第一颗达芬奇(DaVinci)芯片(处理器)DM6446已经问世快三年了.继DM644x之后,TI又陆续推出了D ...