js中的函数编程
之前在网上看到了一篇教你如何用js写出装逼的代码。
经过学些以及扩展很有收获在这里记录一下。
原文章找不到了。所以就不在这附上链接了。
大家看下下面两段js代码。
上面两端代码效果是一模一样的,都是在一个指定的数组中,找到指定的数字所在的下标。第一个大多数人都看得懂。第二个就不一定了。
这里就带大家从一步步最初的版本演化到最终的函数式的版本。
希望大家以后再遇到如此难以阅读的代码,知道怎么去理解。
为了从上面上面变到下面,我们需要了解以下知识。
箭头函数
三元运算符(不讲)
尾递归优化
匿名函数(不讲)
柯里化
高阶函数
其中,尾递归优化,和柯里化,高阶函数,都是函数式编程里面的东西。所以有必要先简单介绍一下什么是函数式编程。
这里先引用下知乎的图。
上面的图并不是说,最下面的最高级,而是越靠下面的越费脑子。
什么是函数式编程?
事实上函数式编程是从范畴论(category theory)发展过来的。而范畴论其实和微积分,数理逻辑,等等都是一种数学理论。而函数式编程只是参考这种思想发展过来的,就像设计模式最初是来源于建筑学一样。
为了更好的理解函数式编程,这里也再简单的介绍下范畴论。高深的我也不懂。。。
在维基百科里面是这么定义的
也就是说只要是存在某种关系,可以从一个对象转化为另外一个对象,那么对象和它们之间的关系就构成一个范畴。
下面的图是一个示意图。
红色的点和黄色的箭头在一起就构成一个范畴。
箭头arrow,还有一个正式的名字叫做态射(morphism)。范畴论认为,同一个范畴的所有成员,就是不同状态的"变形"(transformation)。通过"态射",一个成员可以变形成另一个成员。
上面的很抽象,我们举例子说明下。
大家都对面向对象的思想比较了解,在面向对象的思想里,万事万物都是对象,而对象又可以抽象成为类。比如,黄种人,白种人,黑人。都是对象,可以抽象为人这个类。这是他们有共性。但是他们之间并不存在转化关系,黑人不可能转化为白种人,就算他整容整的很白,概念上他还是个黑人。
而数字1,2,3,4,5。。。他们之间存在一定的关系,1+1可以变成2,2+1可变成3,2+2又可以变成4。我们可以认为,数字和它们之间的态射就是一个范畴。每一个数字,通过一个态势可以变为另外一个数字。
所以范畴包含两部分
- 成员
- 关系
而过度到程序里面就是
- 值
- 函数
简单的来说就是,一个值可以通过一个函数变为另外一个值。所以函数式编程要求每一个函数必须是干净的,进入一个值,出去另外一个值。不会操作任何方法外的数据。
函数式编程有两个最基本的运算。
- 合成
合成的概念就是如果一个值需要经过多个函数才能变成另外一个值,就可以把两个函数合成一个函数。比如1,需要经过add1和add2才能变成4,那么就可以合成一个add3出来。
假设add1=f,add2=g
上面看起来函数有点多,那我们把add1和add2都给匿名了,看起来会好一点
函数的合成还要满足结合律
假设f,g,h分别是add1,add2,add3.
那么(h·g).f 就是 add3(add1(add2)) 而h·(g·f) 就是add1(add2(add3))
他们两者应该是相等的。
2.柯里化
f(x)和g(x)合成为f(g(x)),有一个隐藏的前提,就是f和g都只能接受一个参数。如果可以接受多个参数,比如f(x, y)和g(a, b, c),函数合成就非常麻烦。
这时就需要函数柯里化了。所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。
这里解释一下,柯里化之后是采用的js里面的链式调用。AddX(2)其实返回的是function(x)
{return x+2;} 这时候再跟一个(1),就是把1传入里面执行了。
当然函数式编程还有很多别的东西,这里就不一一介绍了,有兴趣的的可以自己查下。
下面说下, 尾递归优化
我们知道递归的害处,那就是如果递归很深的话,stack受不了,并会导致性能大幅度下降。所以,我们使用尾递归优化技术——每次递归时都会重用stack,这样一来能够提升性能,当然,这需要语言或编译器的支持。Java 就不支持,但是javascript支持。而所谓的支持,就是说编译器会自动优化,对于尾递归的代码会自动优化成。
普通递归。
下面是入栈和出栈的过程。会保存上一步的计算状态,太深的话就会栈溢出。
fac(5)
(5*fac(4))
(5*(4*fac(3)))
(5*(4*(3*fac(2))))
(5*(4*(3*(2*fac(1)))))
(5*(4*(3*2)))
(5*(4*(6)))
(5*24)
120
尾递归
当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归
每次都是执行一个独立的函数,和之前的函数并没有关联。
fac(5,1)
fac(4,5)
fac(3,20)
fac(2,60)
fac(1,120)
120
普通递归创建stack累积而后计算收缩,尾递归只会占用恒量的内存。只需要保存每次计算出来的值,然后传入同一个函数就好。
高阶函数。
高阶函数就是函数当参数,把传入的函数做一个封装,然后返回这个封装函数。上面一直都在用到。
箭头函数
ECMAScript2015 引入的箭头表达式。箭头函数其实都是匿名函数。简单的理解就是通过箭头创建函数。
一个参数时候可以省略小括号,方法体只有一句的时候可以省略大括号
Function (x){return x+1}; 等价于(x) =>{return x+1}或者x=>return x+1;
无参数必须有括号。
Function (){return 1+1} 等价于 ()=>{return 1+1}
如果想加名字的话。
Var add = ()=>{return 1+1}; 调用 add() 就会返回2
该介绍的都介绍了,下面就一步步改造。
原始版本
尾递归优化之后
替换三元运算符
函数体内的函数参数化
转化为箭头函数
匿名
引入高阶函数,并柯里化。
为了方便调用再加上名字
下面断点图帮助理解。
js中的函数编程的更多相关文章
- 5.0 JS中引用类型介绍
其实,在前面的"js的六大数据类型"文章中稍微说了一下引用类型.前面我们说到js中有六大数据类型(五种基本数据类型 + 一种引用类型).下面的章节中,我们将详细讲解引用类型. 1. ...
- 【repost】JS中的异常处理方法分享
我们在编写js过程中,难免会遇到一些代码错误问题,需要找出来,有些时候怕因为js问题导致用户体验差,这里给出一些解决方法 js容错语句,就是js出错也不提示错误(防止浏览器右下角有个黄色的三角符号,要 ...
- JS中给正则表达式加变量
前不久同事询问我js里面怎么给正则中添加变量的问题,遂写篇博客记录下. 一.字面量 其实当我们定义一个字符串,一个数组,一个对象等等的时候,我们习惯用字面量来定义,例如: var s = &quo ...
- js中几种实用的跨域方法原理详解(转)
今天研究js跨域问题的时候发现一篇好博,非常详细地讲解了js几种跨域方法的原理,特分享一下. 原博地址:http://www.cnblogs.com/2050/p/3191744.html 下面正文开 ...
- 关于js中的this
关于js中的this this是javascript中一个很特别的关键字,也是一种很复杂的机制,学习this的第一步就是要明白this既不指向函数自身也不指向函数的词法作用域,this实际上是函数被调 ...
- 表值函数与JS中split()的联系
在公司用云平台做开发就是麻烦 ,做了很多功能或者有些收获,都没办法写博客,结果回家了自己要把大脑里面记住的写出来. split()这个函数我们并不陌生,但是当前台有许多字段然后随意勾选后的这些参数传递 ...
- JS中 call() 与apply 方法
1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...
- 在node.js中,使用基于ORM架构的Sequelize,操作mysql数据库之增删改查
Sequelize是一个基于promise的关系型数据库ORM框架,这个库完全采用JavaScript开发并且能够用在Node.JS环境中,易于使用,支持多SQL方言(dialect),.它当前支持M ...
- 分析js中的constructor 和prototype
在javascript的使用过程中,constructor 和prototype这两个概念是相当重要的,深入的理解这两个概念对理解js的一些核心概念非常的重要. 我们在定义函数的时候,函数定义的时候函 ...
随机推荐
- 高效使用ppt素材
一.素材大致分为: 立体素材:以TG素材为代表的那种高光立体素材 平面素材:以咨询公司麦肯锡.罗兰贝格公司为代表的平面设计的素材 二.使用原则: 原则一:平面左边,立体右边 这个原则告诉你几件事: 如 ...
- Codeforces 2 A. Winner
哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈....... 先让我笑完................ 就是一道撒比题啊,一开始是题目看错= =.是,但是后面还是自己不仔细错的.....不存在题目坑这种情况 ...
- bzoj 3704: 昊昊的机油之GRST【贪心+脑洞】
脑洞题大概 首先处理出每个位置需要操作的次数c,假设第一次达到目标就不能再走,这样的操作次数是c差分后值的正数和,就想成分治每一段然后同减最小值然后从0处断开 然后考虑能一圈一圈走的情况,连续一段多走 ...
- bzoj 3053: The Closest M Points【KD-tree】
多维KDtree板子 左右儿子的估价用mn~mx当区间,假设区间里的数都存在:k维轮着做割点 #include<iostream> #include<cstdio> #incl ...
- bzoj 4310: 跳蚤【后缀数组+st表+二分+贪心】
先求一下SA 本质不同的子串个数是\( \sum n-sa[i]+1-he[i] \),按字典序二分子串,判断的时候贪心,也就是从后往前扫字符串,如果当前子串串字典序大于二分的mid子串就切一下,然后 ...
- 报错org.springframework.dao.DataIntegrityViolationException
最简单的原因可能是数据库外键字段选择了不能为空, 改为允许为空就行了.
- 51Nod 1179 最大的最大公约数(暴力大法好)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; ; in ...
- mybaits 连接数据库汉字保存乱码??
查看数据库连接地址: jdbc.url=jdbc:mysql://localhost:3306/az?useUnicode=true&characterEncoding=utf-8 多了一个a ...
- Caffe实战四(Caffe可视化方法)
面对一堆文件,一行行的数据,确实很难理解深度学习相关的概念,好比训练的数据.构建的网络是怎样的?今天按照书中第16天的内容实践了一翻,终于看到了所谓的深度神经网络的模样.(参考:<深度学习 21 ...
- April Fools Contest 2017 F
Description You are developing a new feature for the website which sells airline tickets: being able ...