zoukankan      html  css  js  c++  java
  • 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也是这种情况。

  • 相关阅读:
    beanstalkd 安装和配置
    vm虚拟机用批处理启动和关闭
    Windows设置VMware开机自动启动,虚拟机也启动
    批处理脚本学习笔记1--vmware虚拟机启停控制
    Shell中uname命令查看系统内核、版本
    SHELL脚本里执行的东西需要多次回车确认,怎么实现自动回车确认?
    eclipse下搭建shell脚本编辑器--安装开发shell的eclipse插件shelled
    如何进行shell脚本正确性测试
    robot framework
    loadrunner参数化数据分配方法
  • 原文地址:https://www.cnblogs.com/zero7room/p/6703243.html
Copyright © 2011-2022 走看看