内容简介:对于ES6的语法的引入,很多时候是我所不理解的,甚至是知道用法(api),却不清楚何使用、为什么用。一次偶然的机会,在Youtube看到了一个系列教程,觉得非常不错,遂记笔记,进行详细的梳理和整合,非常推荐大家去看原版啦,老师是个10年的coder,讲课比小品还生动的(@fun fun function)因为一次可能更新不完,之后有新的内容会更新在github,欢迎小伙伴star,共同进步.从一段程序开始
对于ES6的语法的引入,很多时候是我所不理解的,甚至是知道用法(api),却不清楚何使用、为什么用。一次偶然的机会,在Youtube看到了一个系列教程,觉得非常不错,遂记笔记,进行详细的梳理和整合,非常推荐大家去看原版啦,老师是个10年的coder,讲课比小品还生动的(@fun fun function)
因为一次可能更新不完,之后有新的内容会更新在github,欢迎小伙伴star,共同进步. 传送门
filter
从一段程序开始
var tripe = function(x) {
return x*3;
}
var waffle = tripe;
waffle(3);
复制代码
这是一段简单到不能再简单的代码了,但是,这也是JS的特殊之处。一切皆对象,函数也是对象,函数可以是一个变量(var)。
正式这样的特殊性,让函数可以作为另一个函数的参数(callback)进行传递,这种方式就是高阶函数--函数中包含着另一个函数。下面就从 filter 函数举例来说
现在有一个需求,要找到一个数组中比3大的数字,并拿出来。
先看传统的,不用filter的方案
function big(arr) {
let ret = [];
for(let i = 0; i<arr.length; i++) {
if arr[i] > 3
ret.push(arr[i]);
}
return ret;
}
// 如果现在需求改成找比3小的?再写代码?而且没有复用性。
复制代码
好了,有没有可能简化或者优化下代码呢?让它更具有可维护性,更清楚点? 来看看最简单的函数式编程,使用filter的例子。
var arr = [1,2,3,4];
var b = arr.filter((x)=>{return x >3 });
console.log(b) // [4]
复制代码
好了,可以看到filter接收一个函数作为参数,函数会遍历数组每一个item,当 return 为 true 时,会返回当前的 item 。
这只是一个简单的逻辑,我们说的函数式编程,目的是为了让函数尽量功能简单、逻辑清晰,没有耦合的组织可以让函数复用和代码高效上更有利。所以我们改写下上面的内容
var isBig = function(x) {
return x > 3;
}
var b = arr.filter(isBig);
复制代码
这样子,就完成了解耦,我们就是把函数当作一个变量、参数传给了另一个函数,这就是最基本的思想。 这样做的好处是什么?比如我们现在需要找到比3小的数字,只需要一行代码
var c = arr.reject(isBig); 复制代码
是的,就是这么简单,是不是很神奇? 想想传统的思路,找比3大和比3小是怎么做的?
map
map 是映射的意思,其实和filter很相似,只不过map是映射和变换原数组。什么意思?看下面的需求
一个数组中包含了很多对象,我想要获取这些对象的名字
var animals = [
{name:'cindy', species:'dog'},
{name:'hash', species:'duck'},
{name:'gigi', species:'rabit'},
{name:'chik', species:'cat'},
]
复制代码
好了,传统的做法又是要循环、遍历然后push之后,返回了。用map就很简单
var name = animals.map(obj=>{
return obj.name;
})
复制代码
注意,这就是map和filter的不同: filter遍历,并根据 true 和 flase 决定是否返回原对象(item); map就是纯粹的变换(transform)了。
当然,我们可以利用map,让内容变的更加丰富
var name = animals.map(obj=>{
return `${obj.name}是一个${obj.species}`
})
复制代码
reduce
reduce最基本的用法如下:
var arr = [1,2,3,4,5];
var sum = arr.reduce((sum,next)=>{
return sum + next;
},0)
复制代码
reduce接收两个参数,第一个是 callback ,第二个参数是 初始值 。 arr.reduce(callback(p1,p2),init)
为什么要初始值呢?注意一下回调函数中,是两个参数,p1参数是上一次循环(loop)的返回结果,p2参数是当前遍历到的(item)。 很显然,那么第一次遍历时的p1,就是由 init 提供的。
reduce绝不仅仅是遍历一个数组或者做一个加法这么简单。他可以做更复杂事情,可以对对象进行操作。 比如我们看到这个例子:
var name = [
'sam\tblender\t200\t1 ',
'sam\tpot\t130\t5 ',
'nacy\tconaver\t20\t3 ',
'amy\tpot\t130\t2 ',
'amy\tblender\t4\t2 '
]
复制代码
现在需要统计这个数组中,sam\nacy\amy的个人财产和数据。 怎么办呢? 利用上面介绍的方法组合,可以很好的做到
思路:
- map对每个字符串进行处理和变换
- 使用reduce进行统计
var output =
name.map((item)=>{item.trim().split('\t')})
.reduce((custormers,line)=>{
custormers[line[0]] = custormers[line[0]] || [];
custormers.push({
name: line[0],
property: line[1],
price:line[2]
quilty: line[3]
})
},{})
复制代码
嗯,可能有点复杂了,一行一行来看。
map的作用: 经过map,将原来每一项的字符串,转换成了数组,现在是
这样的形式:
[
[[sam],[blender],[200],[1]],
[[sam],[pot],[130],[5]],
...
]
好了,继续就到了reduce。我们给reduce穿的`init`是一个空对象,也就是
会创建一个对象作为返回值
第一次循环:
custormers:{} line: [[sam],[blender],[200],[1]]
custormers.sam = [];
custormers.sam.push({...})
==> 最终
custormers = {
sam:[{
name:sam,
property:blender,
price:200,
quilty:1
}]
}
第二次循环:
custormers:{sam:[...]} line:[[sam],[pot],[130],[5]]
custormers.sam = [...]
继续为sam这个对象,增加“财产"
...
...
复制代码
所以看到了,这就是reduce的威力。
reduce 实现compose
好了,reduce的作用可能远不止于前面介绍的那些,因为至少我们在菜鸟教程上看的话,会很醒目的告诉你,reduce可以实现 函数compose
我擦,这是什么东西?赶快了解了一下
什么是compose
compose就是执行一系列的任务(函数),比如有以下任务队列
let tasks = [step1, step2, step3, step4] 复制代码
每一个step都是一个步骤,按照步骤一步一步的执行到结尾,这就是一个compose compose在函数式编程中是一个很重要的 工具 函数,在这里实现的compose有三点说明
- 第一个函数是多元的(接受多个参数),后面的函数都是单元的(接受一个参数)
- 执行顺序的自右向左的
- 所有函数的执行都是同步的
面向过程的实现
使用递归的思想,不断的检测任务队列中是否有任务,如果有任务就执行,并把执行结果传递. 实现过程如下
var compose = function(args) {
let length = args.length;
let count = lenth - 1;
let result;
return function inner(...inArgs) {
result = args[count].apply(null,inArgs);
if(coun <= 0) {
return result;
}
count--;
return args[count].apply(null,result);
}
}
复制代码
generator实现
generator是会专门写一个介绍的(就在近期更新),同样是看了很多内容后,理解了它才做的。 因为generator本身就是实现中断、处理、再中断的流程。 generator遇到yield就会抛出一个iterator,而其next()方法可以传递参数,就可以实现传值,将上一步的运行结果,作为下一步的参数。 好了,下面就generator来实现。
function * iterateSteps(steps) {
let param;
steps.forEach((step)=> {
if(param) {
param = yield step.apply(null,param)
} else {
param = yield;
}
})
}
const compose = function(steps) {
let g = iterateSteps(steps); //g是一个generator,通过next()执行
return function(...args) {
let val = steps.pop().apply(null,args) //val返回的值作为将作为第二个函数的参数
//第一个函数无法传参,因此空消耗一个yield
g.next()
return steps.reverse.reduce((result,fn)=>{
g.next(result).value //返回
},val)
}
}
复制代码
解释:
这个可能看起来就有点让人迷糊了。 首先,generator就是一步步来运行函数的,只不过,与普通函数不同,运行到函数的地方,它会把"线程"抛出来,让外面来进行解决。当下次迭代到 next(val) 的时候,会把val值传回。
首先,因为第一次的运行无法传参数,所以我们将param定义,但是不赋值。 在 if-else 中,第一次将走到else,运行 param = yield 。 所以,当第一次运行next的时候,实际只是为了消耗yield。
在compose函数中,首先运行iterataSteps,接下来使用reduce来 自动运行 这个generator,就可以使实现compose了。注意这里 Steps.pop.apply(null,args) 是弹出了最后一个函数,并执行,拿到的值,作为 reduce 的 init 参数。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
模糊数学基础及实用算法
李鸿吉编 / 科学出版社 / 2005-1 / 55.00元
本书开发了模糊数学常用的计算机程序,并以大量的算例系统地介绍了模糊数学的实用算法。本书可以作为模糊数学的应用程序包,在详细解释源代码的同时,对应用程序开发所用到的Visual Basic 6.0方法做了系统介绍,其目的是为读者做进一步的自主开发提供便利。本书所提供的源程序可以作为读者自主开发的素材。本书配有光盘,分章节提供程序源代码。 本书可以作为大专院校、培训班的教学参考书。对需......一起来看看 《模糊数学基础及实用算法》 这本书的介绍吧!