简单聊聊:函数式编程

函数式编程 ( Functional Programming ) 是一种以函数为基础的编程方式和代码组织方式,能够带来更好的代码调试及项目维护的优势。本篇主要结合笔者在实际项目开发中的一些应用,简要谈谈函数式编程。

函数

在函数式编程中,任何代码可以都是函数,且要求具有返回值,如下示例

// 非函数式

var title = "Functional Programming";
var saying = "This is not";
console.log(saying + title); // => This is not Functional Programming
// 函数式

var say = title => "This is " + title;
var text = say("Functional Programming"); // => This is Functional Programming

纯函数

纯函数在这里指函数内外间是“无”关联的。主要有下面两点

  • 没有副作用(side effect)
    不会涉及到外部变量的使用或修改
  • 引用透明
    函数内只会依赖传入参数,在任何时候对函数输入相同的参数时,总能输出相同的结果
// 非纯函数(函数内依赖函数外的变量值)

var title = "Functional Programming";
var say = ()=> "This is not" + title;   // <= 依赖了全局变量 title
// 纯函数

var say = (title)=>"This is " + title; // <= 依赖了以参数 title 传入
say("Functional Programming");

不可变数据(immutable)

这里主要是指变量值的不可变。当需要基于原变量值改变时,可通过产生新的变量来确保原变量的不变性,如下

// 可变数据

var arr = ["Functional", "Programming"];
arr[0] = "Other"; // <= 修改了arr[0]的值
console.log(arr)  // => ["Other", "Programming"] // 变量arr值已经被修改
// 不可变数据

var arr = ["Functional", "Programming"];
// 得到新的变量,不修改了原来的值
var newArr = arr.map(item => {
    if(item === "Functional"){
        return "Other";
    } else {
        return item;
    }
})

console.log(arr);  // => ["Functional", "Programming"] 变量arr值不变
console.log(newArr); // => ["Other", "Programming"]  产生新的变量newArr

之所以使用这种不变值,除了更好的函数式编程外,还能够维持线程安全可靠,落地在业务中,实际上也能让代码更加清晰。
设想,如果你定义了一个变量A,A在其他地方被其他人修改了,这样是不方便定位A的当前值的。关于定义多个变量引发的内存等问题,可以通过重用结构或部分引用的方式来减轻,可参考 immutable.js

使用 map, reduce 等数据处理函数

强大的 JavaScript 有着越来越多的高能处理数据函数,其中包含了 map、 reduce、 filter 等。

map 能够对原数组中的值进行逐个处理并产生新的数组,一个简单例子

// map

var data = [1, 2, 3];
var squares = data.map( (item, index, array) =>  item * item );
console.log(squares); // => [1, 4, 9]
console.log(data);// =>  [1, 2, 3] data 还是那个 data 

reduce 能够对原数组中的各个值进行结合处理,来产生新的值,如下面例子中,previous 代表上一个结果值,current 代表当前值,reduce 函数可以传入第二个参数作为 previous 初始值,不传时则 previous 初始值为数组中第一个值。

// reduce

var sum = [1, 2, 3].reduce( (previous, current, index, array) => previous + current );
console.log(sum); // => 6

函数柯里化 Currying

柯里化 是将多参函数转换成一系列的单参函数。结合下面例子来说明下

// 一个多参函数

var add = (a, b) => a + b;
add(1, 2); // => 3

将上面的多参函数进行柯里化,如下

// 柯里化函数

var add = a => b => a + b;

上面柯里化后的函数调用方式也有所转变,第一次传入一个参数返回了一个函数,再传入参数则完成整体的调用,这也是利用的闭包的特性

var add1 = add(1);
add1(2);  // => 3

柯里化后的函数,也可以应用在生产 “ 函数 ” 上,如下示例

var say = title => type => title + " is " + type;

var sayFP = say("Functional Programming");
var sayOther = say("Other Programming");

sayFP("good"); // => Functional Programming is good
sayOther("good"); // => Other Programming is good

组合函数 compose

顾名思义,组合函数是将多个函数进行组合成一个函数。举个例子

var compose = (fn1, fn2) => (arg) => fn1(fn2(arg));

var a = arg => arg + ‘a‘;
var b = arg => arg + ‘b‘;

var c = compose(a, b); // 将a,b函数进行组合
c(‘c‘);  // => cba

上面示例中,当调用组合函数 c 时,传入的参数会经过 b 函数,接着将 b 函数的返回值作为 a 函数的参数值,从而输出最终结果。
组合函数 c 就像管道一样,将水流( 返回值 )流经各个函数中进行处理。

当想要组合很多函数成一条很长很长的“管道”时,那么显然上面的 compose 函数已经不够用了。下面看看 redux 是怎么做这个 compose 工具函数的。

// 源自: redux/src/compose.js

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  } else {
    const last = funcs[funcs.length - 1]
    const rest = funcs.slice(0, -1)
    return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
  }
}

代码很简洁,主要利用了递归方式和数组的 reduceRight 方法来处理,reduceRight 跟上边提到的 reduce 方法功能是一样的,不同的是 reduceRight 是从数组的末尾向前逐个处理。就这样,想拼多长的就多长。

以上,便是笔者在项目实践中应用较多的函数式编程内容,如有不妥,请斧正。

附: 一些可供学习函数式编程的内容

  • Immutable.js (https://facebook.github.io/immutable-js/)
  • Underscore (http://underscorejs.org/)
  • Lodash (https://lodash.com/)
  • Ramda (http://ramdajs.com/)
  • Mori (http://swannodette.github.io/mori/)
  • Monads (http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html)
时间: 2025-01-02 05:07:07

简单聊聊:函数式编程的相关文章

函数式编程和高阶函数

函数式编程 函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用.而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的. 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数! Python对函数式编程提供部分支持.由于Python允许使用变量,因此,Python不是纯函数式编程语言. 一

python编程:函数式编程和面向对象编程的对比

言而简之,面向对象编程就是把函数编程外面包装一个class类,然后再把这个class类指向一个对象 而class类中的函数在这里称为方法 举个例子: 用函数式编程写出一键发送邮件的脚本: def e_mail(email,message): print('邮件发送中...') return True e_mail('[email protected]','邮件内容') 用面向对象编程写出一键发送邮件的脚本: class Foo: #e_mail称为方法 def e_mail(self,email

函数式编程—高阶函数

一.函数式编程概念简介 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元 就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言:越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言 函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种

javascript函数式编程简单介绍

函数式编程在前端已经成为了一个热门的话题,近几年很多的应用程序代码库里大量使用着函数式编程思想.这里对JavaSctipt中的函数式编程做一个简单介绍. 什么是函数式编程 函数式编程是一种编程范式,主要是利用函数把运算过程封装起来,通过组合各种函数来计算结果.函数式编程意味着开发者可以在更短的时间内编写具有更少错误的代码. 函数式编程的简单例子 假设要把一个字符串转换成每个单词首字母大写,可以这样来实现: var string = 'i do like yanggb'; var result =

20170917 前端开发周报:JavaScript函数式编程、作用域和闭包

1.用函数式编程对JavaScript进行断舍离 当从业20的JavaScript老司机学会函数式编程时,他扔掉了90%的特性,也不用面向对象了,最后发现了真爱啊!!! https://juejin.im/entry/59b86... 2.JavaScript作用域和闭包 作用域和闭包在JavaScript里非常重要.但是在我最初学习JavaScript的时候,却很难理解.这篇文章会用一些例子帮你理解它们.我们先从作用域开始.作用域 JavaScript的作用域限定了你可以访问哪些变量.有两种作

PYTHON修饰器的函数式编程

转自:http://coolshell.cn/articles/11265.html Python修饰器的函数式编程 Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然好像,他们要干的事都很相似--都是想要对一个已有的模块做一些"修饰工作",所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能

Python学习:映射函数(map)和函数式编程工具(filter和reduce)

在序列中映射函数map map函数会对一个序列对象中的每一个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表. 例1: def sum(x):     return x + 10 L1 = [1,2,3,4,5,6,7] L = map(sum, L1) #结果为[11, 12, 13, 14, 15, 16, 17] map还有更高级的使用方法,例如提供了序列作为参数,它能够并行返回分别以每个序列中的元素作为函数对应参数得到的结果的列表.如例2所示. 例2: def sum(

[Java] 函数式编程相关概念 - 笔记1

Java 8 引入了 lambda 表达式,以及函数式编程风格.在了解函数式编程过程中,做了些笔记,摘录于本文. 嵌套函数( Nested Function ) 1. 嵌套函数,是指在另一个函数里面定义的一个函数.外层的函数,这里简称为外层函数. 2. 函数的嵌套可以是多层嵌套.嵌套函数可以看到其全部的外层函数的非局部变量.在实际程序中,嵌套的层数一般很少.下面是一个三层嵌套的例子, innerOfInner 也可以访问在 outer 函数体重定义的变量 x . function outer()

为什么函数式编程在Java中很危险?

摘要:函数式编程这个不温不火的语言由来已久.有人说,这一年它会很火,尽管它很难,这也正是你需要学习的理由.那么,为什么函数式编程在Java中很危险呢?也许这个疑问普遍存在于很多程序员的脑中,作者Elliotte对此发表了一些见解,我们一起来看看他是怎么说的. 在我的日常工作中,我身边的开发者大多是毕业于CS编程顶级院校比如MIT.CMU以及Chicago,他们初次涉及的语言是Haskell.Scheme及Lisp.他们认为函数式编程是一种自然的.直观的.美丽的且高效的编程样式.但奇怪的是,我和我