js 函数式编程 浅谈

js 函数式编程

函数式的思想, 就是不断地用已有函数, 来组合出新的函数。

函数式编程具有五个鲜明的特点:

1. 函数是"第一等公民"

指的是函数与其他数据类型一样,处于平等地位

2. 只用"表达式",不用"语句"

"表达式"(expression)是一个单纯的运算过程,总是有返回值;

"语句"(statement)是执行某种操作,没有返回值。

3. 没有"副作用"

指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),

产生运算以外的其他结果。

4. 不修改状态

变量往往用来保存"状态"(state)。不修改变量,意味着状态不能保存在变量中,

函数式编程使用参数保存状态

5. 引用透明

指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,

引用函数所得到的返回值总是相同的

函数式编程的意义:

1. 代码简洁,开发快速

2. 接近自然语言,易于理解

3. 更方便的代码管理

4. 易于"并发编程"

5. 代码的热升级

---------------------分割线------------------------

在 JavaScript 中,函数本身为一种特殊对象,属于顶层对象,

不依赖于任何其他的对象而存在,因此可以将函数作为传出 / 传入参数,

可以存储在变量中,可以做一切其他对象可以做的事情。

自调用函数(递归--自己调用自己)实际上是高阶函数的一种形式。

函数式编程示例:

// 阶乘的一般实现
function factorial(n) {
  if (n == 1) {
    return 1;
  } else {
    return factorial(n - 1) * n;
  }
}

// 阶乘的函数式编程风格实现
function mul(a, b){  return a*b; }
function dec(x){  return x - 1; }
function equal(a, b){  return a==b; } 

function factorial(n) {
  if (equal(n, 1)) {
    return 1;
  } else {
    return mul(n, factorial(dec(n)));
  }
}

---------------------分割线------------------------

函数柯里化:

是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,

并且返回接受余下的参数而且返回结果的新函数的技术。

我的理解就是需要反复调用一个方法a(),它的参数中有一个参数在一定的状况下的值不易改变,

每次调用都写很多次未免太过麻烦,而且也体现不出来它描述和解决的一类问题,这种情况下,

为了避免这两个问题,我们就将其中那个不容易改变的参数给固定下来,新生成一个函数来应对

这一类问题。

加法柯里化的简单实现:

//加法
function adder(num) {
    return function(x) {
      return num + x;
    }
}

var add5 = adder(5);
var add6 = adder(6);

console.log(add5(1));// 6
console.log(add6(1));// 7

这里的add5表示的函数可以解决基数为5的加法问题,只需要传递一个参数就可以了,

而不必像普通的加法函数那样每次调用都必须添加两个参数。

//计算m的n次方
var powerOfN = function(n){
    return function(m){
        var res = 1;
        for(var i = 0; i < n; ++i){
            res *= m;
        }
        return res;
    } ;
};
//按需生成
var powerOf2 = powerOfN(2);
var powerOf3 = powerOfN(3);
//调用传参
console.log(powerOf2(3));
console.log(powerOf3(2));

柯里化通用实现:

function curry(fn) {
    var args = [].slice.call(arguments, 1);
    return function() {
        var inargs = [].slice.call(arguments);
        console.log(args.concat(inargs));
        return fn.apply(null, args.concat(inargs));
    }
}

function curry(fn) {
    var args = [].slice.call(arguments, 1);
    return function() {
        var inargs = [].slice.call(arguments);
        console.log(args.concat(inargs));
        return fn.apply(null, args.concat(inargs));
    }
}
function add(num1, num2) {
    return num1 + num2;
}
var newAdd = curry(add, 5);
console.log(newAdd(6));

柯里化将降低了函数使用的普遍性,增加了使用的特异性,使用柯里化需要认真识别

其使用的场景,在符合要求的地方使用,不然会显得啰嗦,降低代码的可读性。

---------------------分割线------------------------

高阶函数

高阶函数即为对函数的进一步抽象,就是以其它函数为输入,或者返回一个函数为输出的函数。

高阶函数最常见的应用如 map(映射), reduce(规约), forEach(遍历), filter(过滤)等,

它们都是以传入不同的函数来以不同的方式操作数组元。

简单应用:

function foo(f, g) {
  return function() {
    return f.call(null, g.apply(null, arguments));
    //return f(g.apply(null, arguments)); 也是可以的
  }
}
var sum = function(x, y) {
  return x + y;
}
var square = function(x) {
  return x * x;
}
var squareofsum = foo(square, sum);
squareofsum(2, 3);// 25

下面我们来看一下怎样从过程式编程过渡到函数式编程的:

1>形式一

var sum = function(x, y) {
  return x + y;
}
var square = function(x) {
  return x * x;
}
function foo(){
  return square( sum(2, 3) );
}
foo();// 25

2>形式二

var sum = function(x, y) {
  return x + y;
}
var square = function(x) {
  return x * x;
}
function foo(f, g){
  return f( g(2, 3) );
}
foo(square, sum);// 25

3>形式三

var sum = function(x, y) {
  return x + y;
}
var square = function(x) {
  return x * x;
}
function foo(f, g){
  return function(){
    var num1 = arguments[0];
    var num2 = arguments[1];
    console.log(num1, num2);// 2 3
    var temp = g(num1, num2);
    console.log(temp);// 5
    return f(temp);
  };
}
var myfunc = foo(square, sum);
myfunc(2, 3);// 25

4>形式四

var sum = function(x, y) {
  return x + y;
}
var square = function(x) {
  return x * x;
}
function foo(f, g){
  return function(){
    var temp = g.apply(null, arguments);
    return f(temp);
  };
}
var myfunc = foo(square, sum);
myfunc(2, 3);// 25

最后的形式四就是我们想要得到的效果。

---------------------分割线------------------------

其他示例:

1>

function foo(fn, array, value){
  var res = array.map(function(ele){
    return fn.apply(null, [ele].concat(value));
  });
  return res;
}

function add(x, y) {
  return x + y;
}

function sub(x, y) {
  return x - y;
}

console.log( foo(add, [1, 2, 3], 3) );// [4, 5, 6]
console.log( foo(sub, [1, 2, 3], 3) );// [-2, -1, 0]

2>

function multicast(fn) {
  return function (){
    var pre = arguments[0];
    var rest = arguments[1];
    var ret = pre.map(function(ele) {
      return fn.apply(this, [ele].concat(rest));
    });
    return ret;
  }
}

function add(x, y) {
  return x + y;
}
var newAdd = multicast(add);
console.log(newAdd([1,2,3],3));// [4, 5, 6]

function sub(x, y) {
  return x - y;
}
var newSub = multicast(sub);
console.log(newSub([1,2,3],3));// [-2, -1, 0]

参考资料:

https://blog.oyanglul.us/javascript/functional-javascript.html

http://www.phodal.com/blog/javascript-higher-order-functions/

http://www.cnblogs.com/wing011203/archive/2013/07/07/3176641.html

http://www.ibm.com/developerworks/cn/web/1006_qiujt_jsfunctional/

http://www.cnblogs.com/pigtail/p/3447660.html

http://www.ruanyifeng.com/blog/2012/04/functional_programming.html

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 17:19:20

js 函数式编程 浅谈的相关文章

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', '