Js函数式编程

js 函数式编程

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

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

1. 函数是"第一等公民"
指的是函数与其他数据类型一样,处于平等地位

2. 只用"表达式",不用"语句"
"表达式"(expression)是一个单纯的运算过程,总是有返回值;
"语句"(statement)是执行某种操作,没有返回值。

3. 没有"副作用"
指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),
产生运算以外的其他结果。

4. 不修改状态
变量往往用来保存"状态"(state)。不修改变量,意味着状态不能保存在变量中,
函数式编程使用参数保存状态

5. 引用透明
指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,
引用函数所得到的返回值总是相同的

函数式编程的意义:
1. 代码简洁,开发快速
2. 接近自然语言,易于理解
3. 更方便的代码管理
4. 易于"并发编程"
5. 代码的热升级

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

在 JavaScript 中,函数本身为一种特殊对象,属于顶层对象,
不依赖于任何其他的对象而存在,因此可以将函数作为传出 / 传入参数,
可以存储在变量中,可以做一切其他对象可以做的事情。

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

函数式编程示例:


   
   
  1. // 阶乘的一般实现
  2. function factorial(n) {
  3. if (n == 1) {
  4. return 1;
  5. } else {
  6. return factorial(n - 1) * n;
  7. }
  8. }
  9. // 阶乘的函数式编程风格实现
  10. function mul(a, b){ return a*b; }
  11. function dec(x){ return x - 1; }
  12. function equal(a, b){ return a==b; }
  13. function factorial(n) {
  14. if (equal(n, 1)) {
  15. return 1;
  16. } else {
  17. return mul(n, factorial(dec(n)));
  18. }
  19. }
---------------------分割线------------------------
函数柯里化:
是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,
并且返回接受余下的参数而且返回结果的新函数的技术。

我的理解就是需要反复调用一个方法a(),它的参数中有一个参数在一定的状况下的值不易改变,
每次调用都写很多次未免太过麻烦,而且也体现不出来它描述和解决的一类问题,这种情况下,
为了避免这两个问题,我们就将其中那个不容易改变的参数给固定下来,新生成一个函数来应对
这一类问题。
加法柯里化的简单实现:


   
   
  1. //加法
  2. function adder(num) {
  3. return function(x) {
  4. return num + x;
  5. }
  6. }
  7. var add5 = adder( 5);
  8. var add6 = adder( 6);
  9. console.log(add5( 1)); // 6
  10. console.log(add6( 1)); // 7
这里的add5表示的函数可以解决基数为5的加法问题,只需要传递一个参数就可以了,
而不必像普通的加法函数那样每次调用都必须添加两个参数。

   
   
  1. //计算m的n次方
  2. var powerOfN = function(n){
  3. return function(m){
  4. var res = 1;
  5. for( var i = 0; i < n; ++i){
  6. res *= m;
  7. }
  8. return res;
  9. } ;
  10. };
  11. //按需生成
  12. var powerOf2 = powerOfN( 2);
  13. var powerOf3 = powerOfN( 3);
  14. //调用传参
  15. console.log(powerOf2( 3));
  16. console.log(powerOf3( 2));
柯里化通用实现:


   
   
  1. function curry(fn) {
  2. var args = [].slice.call( arguments, 1);
  3. return function() {
  4. var inargs = [].slice.call( arguments);
  5. console.log(args.concat(inargs));
  6. return fn.apply( null, args.concat(inargs));
  7. }
  8. }
  9. function curry(fn) {
  10. var args = [].slice.call( arguments, 1);
  11. return function() {
  12. var inargs = [].slice.call( arguments);
  13. console.log(args.concat(inargs));
  14. return fn.apply( null, args.concat(inargs));
  15. }
  16. }
  17. function add(num1, num2) {
  18. return num1 + num2;
  19. }
  20. var newAdd = curry(add, 5);
  21. console.log(newAdd( 6));
柯里化将降低了函数使用的普遍性,增加了使用的特异性,使用柯里化需要认真识别
其使用的场景,在符合要求的地方使用,不然会显得啰嗦,降低代码的可读性。
---------------------分割线------------------------
高阶函数
高阶函数即为对函数的进一步抽象,就是以其它函数为输入,或者返回一个函数为输出的函数。
高阶函数最常见的应用如 map(映射), reduce(规约), forEach(遍历), filter(过滤)等,
它们都是以传入不同的函数来以不同的方式操作数组元。
简单应用:


   
   
  1. function foo(f, g) {
  2. return function() {
  3. return f.call( null, g.apply( null, arguments));
  4. //return f(g.apply(null, arguments)); 也是可以的
  5. }
  6. }
  7. var sum = function(x, y) {
  8. return x + y;
  9. }
  10. var square = function(x) {
  11. return x * x;
  12. }
  13. var squareofsum = foo(square, sum);
  14. squareofsum( 2, 3); // 25
下面我们来看一下怎样从过程式编程过渡到函数式编程的:

1>形式一


   
   
  1. var sum = function(x, y) {
  2. return x + y;
  3. }
  4. var square = function(x) {
  5. return x * x;
  6. }
  7. function foo(){
  8. return square( sum( 2, 3) );
  9. }
  10. foo(); // 25
2>形式二


   
   
  1. var sum = function(x, y) {
  2. return x + y;
  3. }
  4. var square = function(x) {
  5. return x * x;
  6. }
  7. function foo(f, g){
  8. return f( g( 2, 3) );
  9. }
  10. foo(square, sum); // 25
3>形式三


   
   
  1. var sum = function(x, y) {
  2. return x + y;
  3. }
  4. var square = function(x) {
  5. return x * x;
  6. }
  7. function foo(f, g){
  8. return function(){
  9. var num1 = arguments[ 0];
  10. var num2 = arguments[ 1];
  11. console.log(num1, num2); // 2 3
  12. var temp = g(num1, num2);
  13. console.log(temp); // 5
  14. return f(temp);
  15. };
  16. }
  17. var myfunc = foo(square, sum);
  18. myfunc( 2, 3); // 25
4>形式四


   
   
  1. var sum = function(x, y) {
  2. return x + y;
  3. }
  4. var square = function(x) {
  5. return x * x;
  6. }
  7. function foo(f, g){
  8. return function(){
  9. var temp = g.apply( null, arguments);
  10. return f(temp);
  11. };
  12. }
  13. var myfunc = foo(square, sum);
  14. myfunc( 2, 3); // 25
最后的形式四就是我们想要得到的效果。

---------------------分割线------------------------
其他示例:

1>


   
   
  1. function foo(fn, array, value){
  2. var res = array.map( function(ele){
  3. return fn.apply( null, [ele].concat(value));
  4. });
  5. return res;
  6. }
  7. function add(x, y) {
  8. return x + y;
  9. }
  10. function sub(x, y) {
  11. return x - y;
  12. }
  13. console.log( foo(add, [ 1, 2, 3], 3) ); // [4, 5, 6]
  14. console.log( foo(sub, [ 1, 2, 3], 3) ); // [-2, -1, 0]

2>


   
   
  1. function multicast(fn) {
  2. return function (){
  3. var pre = arguments[ 0];
  4. var rest = arguments[ 1];
  5. var ret = pre.map( function(ele) {
  6. return fn.apply( this, [ele].concat(rest));
  7. });
  8. return ret;
  9. }
  10. }
  11. function add(x, y) {
  12. return x + y;
  13. }
  14. var newAdd = multicast(add);
  15. console.log(newAdd([ 1, 2, 3], 3)); // [4, 5, 6]
  16. function sub(x, y) {
  17. return x - y;
  18. }
  19. var newSub = multicast(sub);
  20. 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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值