关于阮一峰老师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 = num => num * 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())作为实参并进行第一个函数的调用,第一个函数的运算结果得出后紧接着把这个结果再传给funcs数组里第二个函数作为第二个函数的实参并进行调用,第二个函数的运算结果得出后紧接着再传给第三个函数作为第三个函数的实参并进行调用,以此类推。。。。。。直到funcs数组中的最后一个函数元素执行完毕后,pipeline函数返回的函数的返回值就是reduce()方法的返回值,而reduce()方法的返回值就是funcs数组中最后一个函数参数执行回调函数后返回的值。

return funcs.reduce((prev, fn) => fn(prev), num);

}

const plus1 = num => num + 1;

const mult2 = num => num * 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传递给mult2函数作为mult2函数的实参并执行mult2函数,结果为6*2=12。

console.log(addThenMult(5))

//所以最后devtools中上面两处console.log()打印出的结果分别为:

>>5
>>12

五、最后,再附上一张MDN中对于管道机制的一个示例,也可以帮助更好的理解管道机制的实现原理:

原文地址:https://www.cnblogs.com/tutumiao/p/11725661.html

时间: 2024-08-28 18:39:27

关于阮一峰老师es6(第三版)中管道机制代码的理解浅析的相关文章

unix环境高级编程(第三版)中apue.h文件的配置问题

最近刚开始学习unix环境高级编程(第三版),其中有个作者自己写的apue.h文件,在这归总下相应的配置方法,希望对有需要的朋友们有所帮助 首先http://www.apuebook.com/code3e.html 上去下载相应的压缩包,注意自己书的版本. 下载完成之后,鉴于大多数朋友学习linux都是基于虚拟机的,所以顺便附上虚拟机与本地主机传输文件的方式 首先下载SSH Secure Shell 这个工具,然后直接点击quick connect, 弹出如下界面,输入虚拟机的ip地址,和登录用

关于this的例子解说:引用高级程序第三版中的代码 this在ECMA中介绍的比较复杂。很多我都没看懂。

想要了解THIs的值如何变化的要了解很多知识点.这里我就简单点介绍下this的值如何变化的. 10.1.6 活动对象 当控制进入函数代码的执行上下文时,创建一个活动对象并将它与该执行上下文相关联, 并使用一个名为 arguments.特征为 { DontDelete } 的属性初始化该对象.该属性的初始值是 稍后将要描述的一个参数对象. 接下来,这个活动对象将被用作变量初始化的可变对象. 活动对象纯粹是一种规范性机制,在 ECMAScript 访问它是不可能的.只能访问其成员而 非该活动对象本身

阮一峰老师的ES6入门:async 函数

async 函数 1. 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 Generator 函数,依次读取两个文件. const fs = require('fs'); const readFile = function (fileName) { return new Promise(function (resolve, reject) { fs.readFile(fileNam

阮一峰老师的JavaScript标准参考教程:Object对象和Object方法

Object对象 1. 概述 1.1 生成方法 对象(object)是 JavaScript 语言的核心概念,也是最重要的数据类型. 什么是对象?简单说,对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合. var obj = { foo: 'Hello', bar: 'World' }; 上面代码中,大括号就定义了一个对象,它被赋值给变量obj,所以变量obj就指向一个对象.该对象内部包含两个键值对(又称为两个“成员”),第一个键值对是foo: 'Hello',其中f

flex布局 (引用阮一峰老师的flex布局-语法篇)

一.Flex 布局是什么? Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为 Flex 布局. .box{ display: flex; } 行内元素也可以使用 Flex 布局. .box{ display: inline-flex; } Webkit 内核的浏览器,必须加上-webkit前缀. .box{ display: -webkit-flex; /* Safari */ display: flex; }

阮一峰老师的JavaScript标准参考教程:数组、Array对象和Array对象方法

数组 1. 定义 数组(array)是按次序排列的一组值.每个值的位置都有编号(从0开始),整个数组用方括号表示. var arr = ['a', 'b', 'c']; 上面代码中的a.b.c就构成一个数组,两端的方括号是数组的标志.a是0号位置,b是1号位置,c是2号位置. 除了在定义时赋值,数组也可以先定义后赋值. var arr = []; arr[0] = 'a'; arr[1] = 'b'; arr[2] = 'c'; 任何类型的数据,都可以放入数组. var arr = [ {a:

阮一峰老师JavaScript课程学习笔记

1.switch采用的是严格相等运算符 2.break和continue都具有跳转作用,break语句跳出循环,continue用于立即终止本轮循环,返回循环结构的头部,开始下一轮循环. 3.JavaScript内部所有数字都是以64位浮点数形式存储,涉及小数的运算和比较需要特别小心. (-1)^符号位 * 1.xx...xx * 2^指数位 4.NaN是JavaScript的特殊值,表示"非数字(Not a Number)",主要出现在将字符串解析成数字出错的场合.NaN不等于任何值

分享一个彻底冻结对象的函数——来自阮一峰老师的《ECMAScript 6 入门》

var constantize = (obj) => { Object.freeze(obj); Object.keys(obj).forEach( (key, i) => { if ( typeof obj[key] === 'object' ) { constantize( obj[key] ); } }); }; 冻结对象的用处: 冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性.可配置性.可写性的对象. 也就是说,这个对象永远是不

Wayland (三) Wayland中的跨进程过程调用浅析 [FW]

原文地址:http://blog.csdn.net/jinzhuojun/article/details/40264449 Wayland协议主要提供了Client端应用与Server端Compositor的通信机制,Weston是Server端Compositor的一个參考实现.Wayland协议中最基础的是提供了一种面向对象的跨进程过程调用的功能,在作用上类似于Android中的Binder.与Binder不同的是,在Wayland中Client和Server底层通过domain socke