函数式编程 纯函数 副作用 函数柯里化

函数式编程

函数是一等公民
JS编程特点
1.函数式编程和面向对象编程的混编语言
2.可扩展性
函数式编程
优点:易读 易维护
概念 函数是第一类对象 不依赖任何其他对象独立存在

纯函数

相同的输入得到相同的输出 不依赖且不影响外部环境也不产生任何副作用
输出完全取决于输入
下面就是一个纯函数
两次输入的值相同 两次返回的值也相同

      var a = 1;
      function test(num) {
        console.log(num + 1);
      }
      test(a);

副作用

只要与函数外部环境发生了交互就是副作用
比如 发送数据请求 改变数据 console.log DOM操作 数据的存储(cookie)

      var arr1 = ['a', 'b', 'c', 'd', 'e'],
        arr2 = ['a', 'b', 'c', 'd', 'e'];
      var spArr = arr1.splice(0, 3), //副作用
        slArr = arr2.slice(0, 3); //无副作用
      console.log(arr1);
      console.log(spArr);
      console.log(arr2);
      console.log(slArr);

在这里插入图片描述

函数组合

若干个纯函数 偏函数 柯里化函数组合成一个新的函数 形成数据传递 并实现一种有序执行的效果

      function toUpperCase(str) {
        return str.toUpperCase();
      }
      function exclaim(str) {
        return str + '!';
      }
      function compose(f, g) {
        return function (x) {
          return f(g(x)); //左倾
        };
      }
      var f = compose(exclaim, toUpperCase);
      console.log(f('hello'));

在这里插入图片描述
当参数有多个呢 怎么进行优化

      function toUpperCase(str) {
        return str.toUpperCase();
      }
      function exclaim(str) {
        return str + '!';
      }
      function split(str) {
        return str.split('');
      }
      function reverse(str) {
        return str.reverse();
      }
      function join(str) {
        return str.join('-');
      }
      function compose() {
        var args = Array.prototype.slice.call(arguments),
          len = args.length - 1;
        return function (x) {
          var res = args[len](x);
          while (len--) {
            res = args[len](res);
          }
          return res;
        };
      }
      var f = compose(exclaim, join, reverse, split, toUpperCase);
      console.log(f('hello'));

在这里插入图片描述
方式2 使用reduceRight

      function toUpperCase(str) {
        return str.toUpperCase();
      }
      function exclaim(str) {
        return str + '!';
      }
      function split(str) {
        return str.split('');
      }
      function reverse(str) {
        return str.reverse();
      }
      function join(str) {
        return str.join('-');
      }
      function compose2() {
        var arg2 = Array.prototype.slice.call(arguments);
        return function (x) {
          return arg2.reduceRight(function (res, cb) {
            return cb(res);
          }, x);
        };
      }
      var f = compose2(exclaim, join, reverse, split, toUpperCase);
      console.log(f('hello'));

在这里插入图片描述

左倾

也叫自右向左一次执行
一个函数内部传入一个参数 这个参数是函数执行 这个函数就是左倾的

结合律

在参数中进行函数组合与不分组结果是相同的

      function toUpperCase(str) {
        return str.toUpperCase();
      }
      function exclaim(str) {
        return str + '!';
      }
      function split(str) {
        return str.split('');
      }
      function reverse(str) {
        return str.reverse();
      }
      function join(str) {
        return str.join('-');
      }
      function compose2() {
        var arg2 = Array.prototype.slice.call(arguments);
        return function (x) {
          return arg2.reduceRight(function (res, cb) {
            return cb(res);
          }, x);
        };
      }
      var f = compose2(join, reverse, split);
      var f1 = compose2(compose2(join, reverse), split);
      var f2 = compose2(join, compose2(reverse, split));
      console.log(f('hello'));
      console.log(f1('hello'));
      console.log(f2('hello'));

在这里插入图片描述

pointfree

一些通用的函数组合出各种复杂的运算 上层的运算不要直接操作数据 而通过底层的函数处理
用一种与参数无关的形式合成运算 每一种函数都是一个运算 不需要用代表数据的那个参数

高阶函数

js函数实际上都是指向某一个变量
一个函数可以接收另一个函数作为变量
一个函数接收另一个函数作为参数变量的这个函数就是高阶函数

数组的扩展方法 计时器 sort replace…都是高阶函数
下列函数可以被简化为什么

      var test = function (fn) {
        return doSth(function (data) {
          return fn(data);
        });
      };
      function doSth(fn) {
        fn();
      }
fn(data) -> function(data){return fn(data)}()
var test = function(fn){
	return doSth(fn(data))
}
var test = function(fn){
	fn(data)()
}
var test = fn(data)

函数柯里化

1.简化代码
2.提高维护性
3.功能单一化

功能内聚
降低耦合
降低代码的复用性
提高代码的适应性

      function add(a, b, c, d) {
        return a + b + c + d;
      }
      add(1, 2, 3, 4);
      function curry(fn) {
        var _arg = Array.prototype.slice.call(arguments, 1);
        return function () {
          var newArg = _arg.concat([].slice.call(arguments));
          return fn.apply(this, newArg);
        };
      }
      var add2 = curry(add, 1, 2);
      console.log(add2(3, 4));

在这里插入图片描述
最终优化后的柯里化函数

      function curry(fn, len) {
        var len = len || fn.length;
        var func = function (fn) {
          var _arg = Array.prototype.slice.call(arguments, 1);
          return function () {
            var newArgs = _arg.concat([].slice.call(arguments));
            return fn.apply(this, newArgs);
          };
        };
        return function () {
          var argLen = arguments.length;
          if (argLen < len) {
            var formateArr = [fn].concat([].slice.call(arguments));
            return curry(func.apply(this, formateArr), len - argLen);
          } else {
            return fn.apply(this, arguments);
          }
        };
      }

函数只要被这个curry函数包裹后就可以实现柯里化

改造事件监听函数

我们在之前的文章中封装过一个兼容ie浏览器的事件监听函数

      function addEvent(el, type, fn, capture) {
        if (el.addEventListener) {
          el.addEventListener(type, fn, capture);
        } else if (el.attachEvent) {
          el.attachEvent(
            'on' + type,
            function () {
              fn.call(el);
            }
          );
        } else {
          el['on' + type] = fn;
        }
      }

每次调用这个函数都要进行多次判断
所以这里我们对这个函数进行优化改造

      var addEvent = (function () {
        if (window.addEventListener) {
          return function (el, type, fn, capture) {
            el.addEventListener(type, fn, capture);
          };
        } else if (window.attachEvent) {
          return function (el, type, fn) {
            el.attachEvent('on' + type, function () {
              fn.call(el);
            });
          };
        } else {
          return function (el, type, fn) {
            el['on' + type] = fn;
          };
        }
      })();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_聪明勇敢有力气

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值