js函数式编程

在这篇文章里,我们讨论函数式编程。

  什么是函数式编程?根据百度百科的描述,“函数式编程是种编程典范,它将电脑运算视为函数的计算。函数编程语言最重要的基础是 λ 演算(lambda calculus)。而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。和过程化编程相比,函数式编程里,函数的计算可随时调用。”

  可以看出,在函数式编程中,函数被看做是“一等公民”。JavaScript可以通过巧妙地函数组合来构建抽象,通过内嵌函数的方式,在软件开发的过程中,我们可以把更多的精力放在“函数要做什么”上,而不用太关心“函数如何做”的问题。

  高阶函数

  可以操作其他函数的函数,被称为高阶函数。例如我们想对数组的每一个元素做某种操作,那么我们需要遍历整理数组,当操作发生改变时,我们还要重复编写遍历代码,利用高阶函数,可以简化这个过程。示例如下:

 1 function forEach(array,func){
 2     for(var i = 0; i < array.length; i++){
 3         func(array[i]);
 4     }
 5 }
 6
 7 var a = ["a","b","c"];
 8 forEach(a,function(obj){print(obj);});
 9
10 forEach(a,function(obj){print(obj + 1);});
11
12
13 //输出结果
14 a
15 b
16 c
17 a1
18 b1
19 c1

  forEach函数包含两个参数,第一个参数是一个数组,第二个参数是一个函数,在forEach函数体内,会遍历数组的每一个元素,然后针对每一个元素调用func函数。

  在调用forEach函数时,我们针对第二个参数,使用了匿名函数,它接受一个参数,这个参数其实就是数组中的元素。

  从这个示例中,我们可以看到通过这种方式,可以明显简化对数组的操作。

  修改函数

  我们可以通过高阶函数很方便的修改已有函数的功能,示例如下:

 1 function reverse(func){
 2     return function(value){
 3         return !func(value);
 4     }
 5 }
 6
 7 print(isNaN(NaN));
 8 var isNotNaN = reverse(isNaN);
 9 print(isNotNaN(NaN));
10
11
12 //输出结果
13 true
14 false

  reverse的作用是逆转传入函数的操作,在示例中,isNaN函数返回传入参数是否是NaN。

  规约函数

  Reduce函数通过重复调用一个函数,将数组转换为单一的值。规约函数结构如下:

1 function reduce(combine,base,array){
2     forEach(array, function(value){
3         base=combine(base,value);
4         });
5     return base;
6 }

  Reduce函数中参数的顺序是一个传统,我们可以将第一个参数作为匿名函数的方式传入。

  下面是两个使用Reduce函数的示例,分别计算数组元素的和以及数组中0的个数:

 1 function countZeros(count,value){
 2     return value == 0 ?(count+1) : count;
 3 }
 4
 5 function add(sum,value){
 6     return value+sum;
 7 }
 8
 9 var a=[1,2,3,4,0];
10 print(reduce(add,0,a));
11 print(reduce(countZeros,0,a));
12
13
14 //输出结果
15 10
16 1

  映射函数

  Map函数会遍历数组,针对数组的每个元素,调用指定的操作,然后将操作得出的值存储到另外一个数组中,并返回新数组。

  Map函数的结构如下:

1 function map(func,array){
2     var result=[];
3     forEach(array, function(value){
4         result.push(func(value));
5     });
6     return result;
7 }

  我们可以如下调用map方法:

1 var a=[1,2,3,4,0];
2
3 print(map(function(value){
4                     return value*value;
5                 }, a));
6
7 //输出结果
8 1,4,9,16,0

  这个示例将数组中的每个元素进行平方操作,然后输出。

  其他一些函数技巧

  操作符函数

  在JavaScript学习(1):基础中,我们使用内嵌函数实现了四则运算,接下来我们试着另外一种实现方式:

 1 var a=[1,2,3,4,0];
 2 var ops={"+":function(x,y){return x+y;},
 3         "-":function(x,y){return x-y;},
 4         "*":function(x,y){return x*y;},
 5         "/":function(x,y){return x/y;},
 6         };
 7
 8 function operation(op, array){
 9     if (op in ops){
10         return reduce(ops[op],0,array);
11     }
12     else{
13         throw new Error("invalid operation.");
14     }
15 }
16 print(operation("+", a));
17 print(operation("^", a));
18
19 //输出结果
20 10

  对象中,属性的值不仅仅可以是集合属性,也可以是函数。上述示例使用这种方式对四则运算进行了封装。然后调用reduce方法去计算数组元素的和。

  分布应用

  如果我们需要一个函数,但其中一个操作符的参数已经给定了,那应该如何处理?例如我们想对数组中的每个元素都做加1操作,使用map的方式实现:

1 print(map(function(value){
2             return value + 1;
3         },a));

  在这里,1是放在匿名函数中。我们还可以这样做,使用分布应用的方式在外函数和内嵌函数中分别保存部分参数。

  分布应用的结构如下:

 1 function partial(func){
 2     var knowArgs=arguments;
 3     return function(){
 4         var realArgs=[];
 5         for(var i = 1; i < knowArgs.length; i++){
 6             realArgs.push(knowArgs[i]);
 7         }
 8         for(var i = 0; i < arguments.length; i++){
 9             realArgs.push(arguments[i]);
10         }
11         return func.apply(null, realArgs);
12     }
13 }

  如果想要实现上面同样的功能,代码如下:

1 print(map(partial(ops["+"], 1), a));

  需要注意的是partial函数中在内嵌函数中如何将外函数和内嵌函数的参数进行整合,构成完整的参数列表。

  以a=[1,2,3,4,0]为例,map函数会遍历数组中的每一个元素,当遍历到2时,参数的变化过程:

  1. 外函数参数:1) ops["+"]; 2) 1。

  2. 内嵌函数参数: 2

  3. 完整参数:1,2

  4. func.apply(null, realArgs): ops["+"](1,2)

  函数组合

  函数组合的含义是在调用函数A的过程中,它使用函数B来计算返回结果。

  就像这样:

1 function compose(f1,f2){
2     return function(){
3         return f1(f2.apply(null,realArgs));
4     }
5 }

  上面示例中的isNotNaN也是这种情况。

时间: 2024-10-04 22:22:13

js函数式编程的相关文章

js 函数式编程 浅谈

js 函数式编程 函数式的思想, 就是不断地用已有函数, 来组合出新的函数. 函数式编程具有五个鲜明的特点: 1. 函数是"第一等公民" 指的是函数与其他数据类型一样,处于平等地位 2. 只用"表达式",不用"语句" "表达式"(expression)是一个单纯的运算过程,总是有返回值: "语句"(statement)是执行某种操作,没有返回值. 3. 没有"副作用" 指的是函数内部与外

js函数式编程(1)-纯函数

我将写的第一个主题是js的函数式编程,这一系列都是mostly adequate guide这本书的读书总结.原书在gitbook上,有中文版.由于原作者性格活泼,书中夹杂很多俚语,并且行文洒脱.中文译版难免有时需要思量一番,既然读了就写出来,能方便别人最好,也请读者指正.正文如下. 如果一个函数是纯函数,那么其不依赖外部环境,并且不产生副作用. 1.不依赖外部环境,反例如下: const a1 = 10; const aFunc1 = () => { // 依赖外部变量 return a1;

[原创译书] JS函数式编程 2.3 函数式程序员的工具集

?? Functional Programming in Javascript 主目录第二章 函数式编程基础上一节 与函数共舞 函数式程序员的工具集 如果你仔细看了到目前为止出现过的示例代码,你会发现这里面的一些方法不太熟悉. 它们是map().filter()和reduce()函数,它们对任何语言的函数式编程都至关重要. 它们可以让你不必使用循环和语句,写出更简洁的代码. map().filter()和reduce()函数组成了函数式程序员工具集的核心部分,这个工具集包括一系列纯的. 高阶的函

[原创译书] JS函数式编程 前言

前言 函数式编程是一种能够让你编写更聪明的代码的方式,可以减低复杂度,增强模块化. 它是一种通过灵巧地变化.组合.使用函数达到编写简洁代码的方式. Javascript提供了一个实现这些的超赞的途径.Javascript,这个Internet的脚本语言, 它的核心实际上是一个函数式语言.通过学习如何显露出它作为一个函数式语言的真实身份, 我们可以实现强大的.更易维护的以及更可靠的web应用. 通过这些,Javascript的那些怪癖和缺陷将会立刻变得清晰,并且语言本身也将会无限精彩. 学习如何使

[原创译书] JS函数式编程 2.1 函数式编程语言

?? Functional Programming in Javascript 主目录第二章 函数式编程基础 函数式编程语言 函数式编程语言是那些方便于使用函数式编程范式的语言.简单来说,如果具备函数式编程所需的特征, 它就可以被称为函数式语言.在多数情况下,编程的风格实际上决定了一个程序是否是函数式的. 是什么让一个语言具有函数式特征? 函数式编程无法用C语言来实现.函数式编程也无法用Java来实现(不包括那些通过大量变通手段实现的近似函数式编程). 这些语言不包含支持函数式编程的结构.他们是

JS函数式编程 3.1 Javascript的函数式库

?? Functional Programming in Javascript 主目录第三章 建立函数式编程环境 Javascript的函数式库 据说所有的函数式程序员都会写自己的函数库,函数式Javascript程序员也不例外. 随着如今开源代码分享平台如GitHab.Bower和NPM的涌现,对这些函数库进行分享.变得及补充变得越来越容易. 现在已经有很多Javascript的函数式变成苦,从小巧的工具集到庞大的模块库都有. 每一个库都宣扬着自己的函数式编程风格.从一本正经的数学风格到灵活松

[原创译书] JS函数式编程 3.建立函数式编程环境

?? Functional Programming in Javascript 主目录上一章 函数式编程基础 第三章 建立函数式编程环境 介绍 如果只是为了用函数式编程写应用,我们是否需要了解高级数学知识--类型理论.lambda演算和多态? 我们需要重新发明轮子吗?简单来说,这两个问题的答案都是:不需要. 在这章,我们将竭尽所能去调研所有会影响用Javascript编写函数式程序的方式,包括: 库 工具集 开发环境 编译成Javascript的函数式语言 更多 你要明白现在Javascript

[原创译书] JS函数式编程 2.2 与函数共舞

?? Functional Programming in Javascript 主目录第二章 函数式编程基础上一节 函数式编程语言 与函数共舞 有时,优雅的实现是一个函数.不是方法.不是类.不是框架.只是函数. - John Carmack,游戏<毁灭战士>首席程序员 函数式编程全都是关于如何把一个问题分解为一系列函数的.通常,函数会链在一起,互相嵌套, 来回传递,被视作头等公民.如果你使用过诸如jQuery或Node.js这样的框架,你应该用过一些这样的技术, 只不过你没有意识到. 我们从J

JS函数式编程【译】4.2 函数组合

?? Functional Programming in Javascript 主目录第四章 在Javascript中实现函数式编程的技术 函数组合 终于,我们到了函数组合. 在函数式编程中,我们希望一切都是函数,尤其希望是一元函数,如果可能的话.如果可以把所有的函数转换为一元函数, 将发生神奇的事情. 一元函数是只接受单个输入的函数.函数如果有多个输入就是多元的,不过我们一般把接受两个输入的叫二元函数, 把接受三个输入的叫三元函数. 有的函数接受的输入的数量并不确定,我们称它为可变的. 操作函

Js 函数式编程思想 (V客学院知识分享)

随之ECMAScript 标准规范不断更新,现在已经更新到ES7,不久ES8规范即将面世,为了是JS 语法对函数编程更加友好,诸如 RxJS (ReactiveX) 等函数式框架的不断流行.函数式编程则应该是以函数做为舰载主体,然后对函数进行拆分封装.更加抽象,可扩展性极强. 与传统命令式函数相比存在那些优势? 语法精简清晰 通用性更好 维护及可扩展性更好 限制作用域 以下列举函数对比 // 数组中每个单词,首字母大写 // 一般写法 const arr = ['apple', 'pen', '