javascript函数式编程一例分析

js像其他动态语言一样是可以写高阶函数的,所谓高阶函数是可以操作函数的函数。因为在js中函数是一个彻彻底底的对象,属于第一类公民,这提供了函数式编程的先决条件。
下面给出一个例子代码,出自一本js教程,功能是计算数组元素的平均值和标准差,先列出非函数式编程的一种写法:

var data = [1,1,3,5,5];
var total = 0;
for(var i = 0;i < data.length;i++)
    total += data[i];
var mean = tatal/data.length; //平均数为3
//计算标准差
total = 0;
for(var i = 0;i < data.length;i++){
    var deviation = data[i] - mean;
    tatal += deviation * deviation;
    }
var stddev = Math,.sqrt(total/(data.length-1));//标准差为2

为了使用函数式编程,我们预先定义一些帮助函数(helper functions):

//将类数组对象转换为真正的数组
function array(a,n){
  return Array.prototype.slice.call(a,n||0);
}

//将函数实参传递至左侧
function partial_left(f){
  var args = arguments;
  return function(){
    var a = array(args,1);
    a = a.concat(array(arguments));
    return f.apply(this,a);
  };
}

//将函数的实参传递至右侧
function partial_right(f){
  var args = arguments;
  return function(){
    var a = array(arguments);
    a = a.concat(array(args,1));
    return f.apply(this,a);
  };
}

//该函数实参被用做模版,实参列表中的undefined值会被实际实参值填充。
function partial(f){
  var args = arguments;
  return function(){
    var a = array(args,1);
    var i = 0,j = 0;
    for(;i<a.length;i++)
      if(a[i] === undefined)
        a[i] = arguments[j++];
    a = a.concat(array(arguments,j));
    return f.apply(this,a);
  };
}

//返回一个函数类似于f(g())
function compose(f,g){
  return function(){
    return f.call(this,g.apply(this,arguments));
  };
}

下面我们给出完全用函数式编程的js代码:

var data = [1,1,3,5,5];
var sum = function(x,y){return x+y;};
var product = function(x,y){return x*y;};
var neg = partial(product,-1);
var square = partial(Math.pow,undefined,2);
var sqrt = partial(Math.pow,undefined,0.5);
var reciprocal = partial(Math.pow,undefined,-1);

//好吧,高潮来鸟 :)
var mean = product(reduce(data,sum),reciprocal(data.length));
var stddev = sqrt(product(reduce(map(data,compose(square,partial(sum,neg(mean)))),sum),reciprocal(sum(data.length,-1))));

除了reduce和map函数,其他函数前面都给出了。reduce函数类似与ruby中的inject函数:

ary = (1..10).to_a
ary.inject(0) {|sum,i|sum + i} //结果为55

js的写法如下:

var ary = [1,2,3,4,5,6,7,8,9,10]
ary.reduce(function(sum,i){
  return sum + i;
},0);

0为sum的初始值,如果省略则sum为数组第一个元素的值,这里可以省略。

map函数也很简单,类似与对数组的每一个元素做操作,然后返回一个经过操作后的数组,就以ruby代码为例,js代码与此类似:

a = (1..3).to_a; #数组[1,2,3]
a.map {|x| x*2} #返回新数组[2,4,6]

下面我们来分析下那一长串的代码:)
sum和product定义了元素相加和相乘的函数;
neg也是一个函数功能等价于:product(-1,x),即对x值求负;
square函数等价于:Math.pow(x,2),即计算x的平方值,注意这里partial的第二个参数是undefined,这意味着这里的形参会被第一个实参填补(见前面partial的代码);再说的明白点:square(x)功能等于Math.pow(x,2)。
sqrt函数和square类似,功能等价于:Math.pow(x,0.5),相当于计算x的开二次方。
最后一个函数reciprocal也没什么难度,等价于:Math.pow(x,-1),即计算x的负一次方,相当于计算x的倒数。
下面就是如何把上面各种函数揉捏在一起鸟 :)
先看平均值的计算,很简单:就是先计算数组元素的和然后乘上数组长度的倒数,即数组和/数组长度。
最后来看貌似很难的标准差,我们最好由内向外看:
先看包含neg的那层:

//等价于函数sum(-1 * mean + x)
partial(sum,neg(mean)

下面看compose函数:

//下面在源代码上做了等价替换,可以再次等价于:
//square(sum(-1*mean + x)),再次展开(我剥,我剥,我剥洋葱...):
//Math.pow(sum(-1*mean + x),2);
compose(square,sum(-1*mean + x))

接下来看map函数:

//很清楚吧!?即data中每一个元素都为一个x,将其传入后面的函数,然后返回一个计算后的新数组,即新数组中的每个元素的值是data中的每个元素加上data负的平均数,然后对其结果计算2次方的结果。
map(data,Math.pow(sum(-1*mean + x),2))

再接着看map外面的reduce函数:

//将前面新数组的每个元素值加起来。
reduce(map(...),sum)

然后看一下reciprocal函数:

//等价于求(data.length-1)的倒数
reciprocal(sum(data.length,-1))

再看外层的product函数:

//等价于新数组元素的和除以(data.length-1)
product(reduce(...),reciprocal(...))

最外层的sqrt表示对以上除法得出的结果求平方根;大家可以对照一下前面非函数编程的代码,是一样一样滴 :) 看似蛮怕人的一大坨代码,展开分析后难度立马将至零。如果各位看官最后表示还是未看明白,那完全是本猫语言表达能力的问题,欢迎提问。
解释完毕,打完收功,大功告成。

时间: 2024-09-20 00:55:51

javascript函数式编程一例分析的相关文章

javascript函数式编程实例分析

  这篇文章主要介绍了javascript函数式编程,实例分析了javascript函数式编程的相关使用技巧,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了javascript函数式编程.分享给大家供大家参考.具体分析如下: js像其他动态语言一样是可以写高阶函数的,所谓高阶函数是可以操作函数的函数.因为在js中函数是一个彻彻底底的对象,属于第一类公民,这提供了函数式编程的先决条件. 下面给出一个例子代码,出自一本js教程,功能是计算数组元素的平均值和标准差,先列出非函数式编程的一种写法

javascript函数式编程实例分析_javascript技巧

本文实例讲述了javascript函数式编程.分享给大家供大家参考.具体分析如下: js像其他动态语言一样是可以写高阶函数的,所谓高阶函数是可以操作函数的函数.因为在js中函数是一个彻彻底底的对象,属于第一类公民,这提供了函数式编程的先决条件. 下面给出一个例子代码,出自一本js教程,功能是计算数组元素的平均值和标准差,先列出非函数式编程的一种写法: var data = [1,1,3,5,5]; var total = 0; for(var i = 0;i < data.length;i++)

探究JavaScript函数式编程的乐趣_javascript技巧

编程范式 编程范式是一个由思考问题以及实现问题愿景的工具组成的框架.很多现代语言都是聚范式(或者说多重范式): 他们支持很多不同的编程范式,比如面向对象,元程序设计,泛函,面向过程,等等. 函数式编程范式 函数式编程就像一辆氢燃料驱动的汽车--先进的未来派,但是还没有被广泛推广.与命令式编程相反,他由一系列语句组成,这些语句用于更新执行时的全局状态.函数式编程将计算转化作表达式求值.这些表达式全由纯数学函数组成,这些数学函数都是一流的(可以被当做一般值来运用和处理),并且没有副作用. 函数式编程

我眼中的JavaScript函数式编程

JavaScript 函数式编程是一个存在了很久的话题,但似乎从 2016 年开始,它变得越来越火热.这可能是因为 ES6 语法对于函数式编程更为友好,也可能是因为诸如 RxJS (ReactiveX) 等函数式框架的流行. 看过许多关于函数式编程的讲解,但是其中大部分是停留在理论层面,还有一些是仅针对 Haskell 等纯函数式编程语言的.而本文旨在聊一聊我眼中的函数式编程在 JavaScript 中的具体实践,之所以是 "我眼中的" 即我所说的仅代表个人观点,可能和部分 严格概念 

Javascript函数式编程简单介绍_javascript技巧

几十年来,函数式编程一直是计算机科学狂热者的至爱,由于数学的纯洁性和谜一般的本质, 它被埋藏在计算机实验室,只有数据学家和有希望获得博士学位的人士使用.但是现在,它正经历一场复兴, 这要感谢一些现代语言比如Python,Julia,Ruby,Clojure以及--但不是最后一个--Javascript. 你是说Javascript?这个WEB脚本语言?没错! Javascript已经被证明是一项长期以来都没有消失的重要的技术.这主要是由于它扩展的一些框架和库而使其具有重生的能力, 比如backb

浅谈javascript函数式编程_javascript技巧

函数式编程,属于编程范式的一种 1 函数是第一公民,可以返回值,也可以作为其他函数的参数 //console是一个函数 function con(v){ console.log(v) } // execute 也是一个函数 function execute(fn){ fn(1) } //将con函数作为参数传进execute函数 execute(con) // 1 2 接近自然语言的写法   晓池吃完饭然后就去洗澡 可以表现为eat().bathe() // 吃饭函数 function eat(

《JavaScript函数式编程》读后感_javascript技巧

本文章记录本人在学习 函数式 中理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习. 在近期看到了<JavaScript函数式编程>这本书预售的时候就定了下来.主要目的是个人目前还是不理解什么是函数式编程.在自己学习的过程中一直听到身边的人说面向过程编程和面向对象编程,而函数式就非常少.为了自己不要落后于其他同学的脚步,故想以写笔记的方式去分享和记录自己阅读中所汲取的知识. js 和函数式编程 书中用了一句简单的话来回答了什么是函数式编程: 函数式编程通过使用函数来将值转换为抽象单元

了解JavaScript函数式编程(一)

一.引言 说到函数式编程,大家可能第一印象都是学院派的那些晦涩难懂的代码,充满了一大堆抽象的不知所云的符号,似乎只有大学里的计算机教授才会使用这些东西.在曾经的某个时代可能确实如此,但是近年来随着技术的发展,函数式编程已经在实际生产中发挥巨大的作用了,越来越多的语言开始加入闭包,匿名函数等非常典型的函数式编程的特性,从某种程度上来讲,函数式编程正在逐步"同化"命令式编程. JavaScript 作为一种典型的多范式编程语言,这两年随着React的火热,函数式编程的概念也开始流行起来,R

javascript 函数式编程_javascript技巧

JavaScript的函数式编程的对象本质: function a() {     var x="sth";       return b(){         //do with x;      } } var c = a(); 等价于 function a() {         this.x = "dosth";         this.b = function(){               //do with this.x         } } va