博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
常见的函数式编程模型
阅读量:4631 次
发布时间:2019-06-09

本文共 2502 字,大约阅读时间需要 8 分钟。

1.闭包(Closure)

闭包的概念

可以保留局部变量不被释放的代码块,被称为一个闭包。

闭包的特点:函数嵌套函数、内部函数可以引用外部函数的参数和变量、参数和变量不会被垃圾回收机制收回

// 创建一个闭包function makeCounter() {  let k = 0;  return function() {    return ++k;  };}const counter = makeCounter();console.log(counter());  // 1console.log(counter());  // 2

makeCounter 这个函数的代码块,在返回的函数中,对局部变量 k ,进行了引用,导致局部变量无法在函数执行结束后,被系统回收掉,从而产生了闭包。而这个闭包的作用就是,“保留住“ 了局部变量,使内层函数调用时,可以重复使用该变量;而不同于全局变量,该变量只能在函数内部被引用。 

换句话说,闭包其实就是创造出了一些函数私有的 ”持久化变量“。 

所以从这个例子,我们可以总结出,闭包的创造条件是: 

(1)存在内、外两层函数    (2)内层函数对外层函数的局部变量进行了引用

闭包的用途

闭包的主要用途就是可以定义一些作用域局限的持久化变量,这些变量可以用来做缓存或者计算的中间量等等。

// 简单的缓存工具// 匿名函数创造了一个闭包const cache = (function() {  const store = {};    return {    get(key) {      return store[key];    },    set(key, val) {      store[key] = val;    }  }}());cache.set('a', 1);cache.get('a');  // 1

上面例子是一个简单的缓存工具的实现,匿名函数创造了一个闭包,使得 store 对象 ,一直可以被引用,不会被回收。 

闭包的弊端:持久化变量不会被正常释放,持续占用内存空间,很容易造成内存浪费,所以一般需要一些额外手动的清理机制。

2.高阶函数 

接受或者返回一个函数的函数称为高阶函数,JavaScript 中见到许多原生的高阶函数,例如 Array.map , Array.reduce , Array.filter 

以map函数方法为例:

  map:映射是对集合而言的,即把集合的每一项都做相同的变换,产生一个新的集合

// 数组中每一项加一,组成一个新数组// 一般写法const arr = [1,2,3];const rs = [];for(const n of arr){  rs.push(++n);}console.log(rs)// map改写const arr = [1,2,3];const rs = arr.map(n => ++n);

上面一般写法,利用 for...of 循环的方式遍历数组会产生额外的操作,而且有改变原数组的风险 

而 map 函数封装了必要的操作,使我们仅需要关心映射逻辑的函数实现即可,减少了代码量,也降低了副作用产生的风险。

柯里化(Currying)

给定一个函数的部分参数,生成一个接受其他参数的新函数,叫做函数的柯里化。

柯里化可以使我们只关心函数的部分参数,使函数的用途更加清晰,调用更加简单。 

//一般写法function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {  if( n <= 1 ) {
return ac2}; return Fibonacci2 (n - 1, ac2, ac1 + ac2);}// 柯里化function currying(fn, n1, n2) { return function (m) { return fn.call(this, m, n1, n2); };}function tailFibonacci(n, ac1, ac2){ if( n <= 1 ) {
return ac2}; return tailFibonacci (n - 1, ac2, ac1 + ac2); }const Fibonacci4 = currying(tailFibonacci,1,1);Fibonacci4(100) // 573147844013817200000

4.组合

将多个函数的能力合并,创造一个新的函数,叫做组合。

// 数组中每个单词大写,做 Base64// 一般写法 (其中一种)const arr = ['pen', 'apple', 'applypen'];const rs = [];for(const w of arr){  rs.push(btoa(w.toUpperCase()));}console.log(rs);// _.flow 改写const arr = ['pen', 'apple', 'applypen'];const upperAndBase64 = _.partialRight(_.map, _.flow(_.upperCase, btoa));console.log(upperAndBase64(arr));

_.flow 将转大写和转 Base64 的函数的能力合并,生成一个新的函数。方便作为参数函数或后续复用。 

总结

我理解的 JavaScript 函数式编程,可能和许多传统概念不同。我并不只认为 高阶函数 算函数式编程,其他的诸如普通函数结合调用、链式结构等,我都认为属于函数式编程的范畴,只要他们是以函数作为主要载体的。 

而我认为函数式编程并不是必须的,它也不应该是一个强制的规定或要求。与面向对象或其他思想一样,它也是其中一种方式。我们更多情况下,应该是几者的结合,而不是局限于概念。 

 

参考来源:

转载于:https://www.cnblogs.com/guorange/p/7146399.html

你可能感兴趣的文章
总结技术人生的第一个“五年计划”
查看>>
linux (一)
查看>>
名不正,则言不顺
查看>>
实验报告四
查看>>
wp8公司帐号申请注意事项
查看>>
PowerDesigner 中将Comment(注释)及Name(名称)内容互相COPY的VBS代码
查看>>
.Net程序员学用Oracle系列(14):子查询、集合查询
查看>>
contest16 CF315 div2+div1F oooxox oooxox oooooo
查看>>
ubuntu下如何用命令行运行deb安装包
查看>>
luacom cygwin
查看>>
『ACM C++』 PTA 天梯赛练习集L1 | 044-45
查看>>
Duilib
查看>>
hdu--2545--数据弱了?
查看>>
链接思维导图 -读《深入理解计算机系统》
查看>>
PostgreSQL窗口函数
查看>>
学习笔记(一)
查看>>
android一体机的开发问题
查看>>
java中equals和==的区别
查看>>
bzoj3675: [Apio2014]序列分割
查看>>
LC-349 两个数组的交集
查看>>