从函数式编程和面向对象的思考到Vue3的函数式编程

概要:函数式编程和面向对象是日常编程中非常常见的。在前端项目的开发中,经常是面向对象与函数式编程混合使用,本文进行案例函数式与面向对象的一些对比。然后从hook的角度引入函数式组件再到vue3的函数式编程。也有部分java的lambda与stream流的函数式编程。

一 、数据的处理方式

1.1数据存放方式决定了访问的方式。

1、对于OO来说,访问数据(全局变量除外)需要先获取对象的引用,然后再进行操作(直接访问——公共属性,或者调用成员函数/方法访问——私有属性)

2、对于函数式,访问数据是直接访问(通过函数入参或者作用域链查找)

//OO
class Foo {
    
    
  constructor(){
    
    
    this.bar = 0
  }
}
let foo = new Foo()
foo.bar ++

//函数式

let bar = 0
function foo(){
    
    
    bar ++
}
foo()

从代码上可以看出,函数式编程更加的简洁。函数式编程调用数据的时候不需要先new 出对象再去考虑操作,而是以着函数优先的角度去考虑问题。
在函数式编程中。所有的数据都是不可变的,不同的函数之间通过数据流来交换信息,函数作为一等公民,享有跟数据一样的地位,可以作为参数传递给下一个函数,同时也可以作为返回值。

二、灵活性与性能

2.1 所有的数据都是不可变的,所以所有的变量在程序运行期间都是一直存在的,非常占用运行资源
2.2 函数式编程在大规模工程如果对函数式编程的理解不够深刻就会出现晦涩难懂的局面。
2.3 函数式写法更加灵活,更加符合语义。
2.4.在函数式编程中,编程的主要重点是我们在做什么。在面向对象的编程中,编程的主要重点是我们如何做。

三、前端项目中的应用

3.1 hook的使用

  1. 简要介绍hook
    1.1 react中对于function component来说只能拥有props,不能拥有state,也就是只能实现stateless component。react 并没有提供在函数组件中设置state以及生命周期的一些操作方法,所以那个时候,极少的场景下适合采用函数组件。
    1.2 hook的目标就是–让你在不编写 class 的情况下使用 state 以及其他的 React 特性
  2. hook的意义
    框架是服务于业务的,业务中很难避免的一个问题就是-- 逻辑复用,同样的功能,同样的组件,在不一样的场合下,我们有时候不得不去写2+次,为了避免耦合,后来各大框架纷纷想出了一些办法:
    2.1 mixin react 和 vue都曾用过mixin(react 目前已经废弃),
    2.2 HOC Higher-Order-Components(HOC) react中用的相对多一点,vue的话,嵌套template有点。。别扭,
    2.3 slot slot vue中用的多一些,react基本不需要slot这种用法

react官网案例 useState

import React, {
    
     useState } from 'react';

function Example() {
    
    
  // 声明一个新的叫做 “count” 的 state 变量
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {
    
    count} times</p>
      <button onClick={
    
    () => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

总结
1.function component 将会是接下来各大框架发展的一个方向,function天然对TS的友好也是一个重要的影响;
2.react hook的上手成本相对于vue会难一些,vue天生规避了一些react中比较难处理的地方;
3.hook一定是大前端的一个趋势
这部分借鉴:https://blog.csdn.net/weixin_33929309/article/details/93164243

3.2 vue3的函数式编程

vue2是将mounted,data,computed,watch之类的方法作为一个对象的属性进行导出。
vue3新增了一个名为setup的入口函数,value, computed, watch, onMounted等方法都需要从外部import。
在vue3中,我们可以像写一个方法一样去写这个组件的JS逻辑部分,使用import来按需引入。这样的好处显而易见,首先就是我们需要写的代码量少了,其次就是我们可以封装更多的子函数、引用更多的公共函数去维护我们的代码,第三就是代码的可读性变高了。(当然,我们的打包体积也会变小)

vue2的代码组织结构

<script>
  import ueditor from 'ueditor'
  export default {
    
    
    data () {
    
    
      return {
    
    
        ue: null,
        ueId: `J_ueditorBox_${
      
      new Date().getTime()}`,
        ueContent: '',
        dialogVisible: false
      }
    },
    mounted () {
    
    
      this.ue = ueditor.getEditor(this.ueId, {
    
    
        // serverUrl: '', // 服务器统一请求接口路径
        zIndex: 3000
      })
    },
    methods: {
    
    
      getContent () {
    
    
        this.dialogVisible = true
        this.ue.ready(() => {
    
    
          this.ueContent = this.ue.getContent()
        })
      }
    }
  }
</script>

vue3的函数式编程

<script>
import {
    
     value, computed, watch, onMounted } from 'vue'

export default {
    
    
  setup() {
    
    
    // reactive state
    const count = value(0)
    // computed state
    const plusOne = computed(() => count.value + 1)
    // method
    const increment = () => {
    
     count.value++ }
    // watch
    watch(() => count.value * 2, val => {
    
    
      console.log(`count * 2 is ${
      
      val}`)
    })
    // lifecycle
    onMounted(() => {
    
    
      console.log(`mounted`)
    })
    // expose bindings on render context
    return {
    
    
      count,
      plusOne,
      increment
    }
  }
}
</script>

四、java项目中的函数式编程

java项目中的函数式编程的使用感觉和前端项目中是很不一样的。java中使用函数式编程可以极大的减轻代码量,但是归根结构还是在为对象的某些属性或者方法服务。
4.1 下面简单的以线程的这个简单的经典案例举例子。借用lambda表达式,省略了new Runnable()的过程,并且直接重写父类的run方法,不需要@Override

public static void main(String[] args) {
    
    
  // Java7
  new Thread(new Runnable() {
    
    
    @Override
    public void run() {
    
    
      for (int i = 0; i < 100; i++) {
    
    
        System.out.println(i);
      }
    }
  }).start();

  // Java8
  new Thread(() -> {
    
    
    for (int i = 0; i < 100; i++) {
    
    
      System.out.println(i);
    }
  }).start();
}

4.2 也应用比较多的场景有stream流数据的转换

  		// 2.查询所有属性
  		List<AttrGroupEntity> attrGroupEntities = this.getData();
        List<AttrGroupWithAttrsVo> collect = attrGroupEntities.stream().map((item) -> {
    
    
        	// 对原有对象 AttrGroupEntity 处理封装出新的对象 AttrGroupWithAttrsVo
            AttrGroupWithAttrsVo attrGroupWithAttrsVo = new AttrGroupWithAttrsVo();
            BeanUtils.copyProperties(item,attrGroupWithAttrsVo);

            // 查询出属性分组的id然后赋值
            List<AttrEntity> relationAttr = attrService.getRelationAttr(item.getAttrGroupId());
            
            attrGroupWithAttrsVo.setAttrs(relationAttr);

            return attrGroupWithAttrsVo;
        }).collect(Collectors.toList());

五、小结

1.目前的项目中前端中体现的函数式编程比较多,后端更多的还是OOP的思想。
2.在大型的偏向工程话的项目中,使用面向对象的方式方便拓展,更易编写。在项目中的比较小的一些组织模块可以使用函数式编程来提高效率。

猜你喜欢

转载自blog.csdn.net/qq_21561833/article/details/118969397
今日推荐