小丸子函数式编程初探

Posted 小章鱼哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小丸子函数式编程初探相关的知识,希望对你有一定的参考价值。

小丸子函数式编程初探

1. question

前一个项目,顺利完成的时候感觉特别棒。但是后面需求方迭代加需求的时候,甚至代码重构的时候,感觉特别乏力。

当时说不出来问题在哪,但是感觉自己写的代码维护成本很高,加需求的时候需要四处去改。

考虑一下,大概有以下几个方面做的不够好:

  1. 组件设计

项目的复杂组件在所选的技术栈上并没有例子( nej + regular)。所以不得已,复杂组件都是自己手写定制的。项目周期又比较紧,以至于,有一两个组件,特别复杂,其实并没有封装的好,而且是同事在我的组件基础上继续改变成另一个组件。这个时候组件设计的问题就暴露出来了。很多逻辑并没有抽离好,当后面组件越来越庞大的时候,手忙脚乱。

有一句话说的很好,

数据结构设计的不合理,这个组件就已经失败了(原话我忘了,这是我翻译的,是这个意思。)

  1. 编程方式

最近尝试使用组内大佬(他是函数式编程小王子)编写的一堆高阶函数,用它们来简化一些常用函数和操作。感觉特别棒。

甚至震惊我的是:有一个页面,我预估一天可以写完,但是我尝试用大佬的高阶函数封装的一套数据与操作绑定的小框架(我词穷,就当小框架吧)来实现的时候,我一小时就把页面写完了,而且代码量很小很干净。

顿时感觉自己之前写的代码low爆了。

  1. 回调地狱

目前项目各种使用promise了。

有时间深入研究。


本文研究一下关于编程方式:函数式编程

下面带大家看看不同的编程方式,对于项目的开发及其维护,多么重要吧。

2. 函数式编程

1. 命令式编程 vs 函数式编程

先看一个例子吧。

<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <div id="switcher" class="on"></div>
    <script>
      const switcher = document.querySelector('#switcher');
      function changeColor(evt) 
        const target = evt.target;
        if (target.className === 'on') 
          target.className = 'off';
         else 
          target.className = 'on';
        
      
      switcher.onclick = changeColor;
    </script>
    <style>
      #switcher 
        width: 100px;
        height: 100px;
        border: solid 1px white;
        border-radius: 50px;
      
      .on 
        background-color: green;
      
      .off 
        background-color: red;
      
    </style>
  </body>
</html>

这段代码实现的效果是页面上有一盏红绿灯,每点击一次,就进行一次红/绿切换。

核心代码是这个函数。

function changeColor(evt) 
        const target = evt.target;
        if (target.className === 'on') 
          target.className = 'off';
         else 
          target.className = 'on';
        
      

我上一个项目,大量充斥着这样的代码,if``else满天飞。

现在是红灯绿灯切换,如果加一个黄灯,又要加一堆if``else。是不是维护成本挺高的。

用函数式的思维来实现是这个样子的:

const switcher = document.querySelector('#switcher');

      function toggleQueue(...actions) 
        return (...args) => 
          const act = actions.shift();
          actions.push(act);
          return act.apply(this, args);
        

      
      switcher.onclick = toggleQueue(
        // evt => evt.target.className = 'yellow',
        evt => evt.target.className = 'off',
        evt => evt.target.className = 'on'

      );

需要黄灯只需要加一句evt => evt.target.className = 'yellow'就可以了。

2. 高阶函数

输入是函数或者输出是函数的函数。(这也是我翻译的,是这个意思)

3. 实用小栗子

本文几个函数式编程的小例子,都是项目中最常用的功能,希望给函数式编程小白一些启发。

// 函数节流
function throttle(fn, timer = 500) 
  let time;
  return (...args) => 
    if (!time) 
      fn.apply(this, args);
      time = setTimeout(() => 
        time = null;
      , timer);
    
  


function call() 
  console.log('hello');


switcher.onclick = throttle(call);
// 只生效一次
function once(fn) 
  return (...args) => 
    if (fn) 
      fn.apply(this, args);
      fn = null;
    
  



function call() 
  console.log('hello');


switcher.onclick = once(call);
// 链式调用
function chain(fn) 
  return (...args) => 
    fn.apply(null, args);
      return this;
  


function call() 
  console.log('hello');


function write() 
  console.log('write');

call = chain(call);
write = chain(write);
call().write();
// 批量处理
function pack(map) 
  return (obj) => 
    for(let key in obj) 
      map[key].call(this, obj[key]);
    
  


function call(name) 
  console.log('call ' + name);


function write(name) 
  console.log('write ' + name);

let css = pack(call: call, write: write)

css(call: 'hello', write: 'world');

我的理解是,函数式的设计就是把一个个功能剥离出来,实现为高阶函数,给最基础的函数附加上一系列的功能。

参考:
http://www.zcfy.cc/article/javascript-and-functional-programming-an-introduction

http://www.zcfy.cc/article/imperative-vs-declarative

以上是关于小丸子函数式编程初探的主要内容,如果未能解决你的问题,请参考以下文章

响应式编程库 RxJava 初探

小丸子看vue如何响应式

[2.0] 函数式编程初探

函数式编程初探

初探Java8lambda表达式

[转] 函数式编程初探