九月任务

78 阅读8分钟

1.函数式编程的理解(面向对象编程的理解)
2.vue中component API和react hook的区别
3.hooks时代,如何写出高质量的react和vue组件(组件的理解) 4.前端脚手架
5.qiankun落地相关问题
6.修改第三方依赖源码并同步项目组
7.前端部署的基本概念

1.函数式编程的理解

1. 函数式编程的概念

函数式编程
函数式编程是声明式编程的一种,例如我们常写的sql语句就是典型的声明式编程:select * from table where id = 1;
但是又不局限于声明式编程。但是函数式编程继承了声明式编程的思想:只关注做什么而不怎么做。函数式编程中的函数,确切的说是一种对函数参数和函数结果的映射关系。

2. 命令式编程和面向对象编程的特点

函数式编程和面向对象编程的区别 Javascript是一种多范式语言,这就意味着我们可以在一段javascript代码中使用多种不同的编程范式:命令式编程、面向对象编程、函数式编程。

1.命令式编程
命令式编程,抽象点说就是我们在编程的时候需要指明计算机每一步需要执行的步骤。简单点就是说我们平时编写的while循环、for循环、条件分支等编程语句,来实现我们的功能。

2.面向对象编程
面向对象编程就是三个特点:封装、继承、多态。zhuanlan.zhihu.com/p/51832983 image.png js实现三大特性的方式:
封装的实现:一般是通过“闭包”;
继承的实现:一般有六种:借用构造函数、原型链继承、组合继承、原型式继承、寄生继承、寄生组合继承
多态的实现:通过对传递参数的判定来执行特定的逻辑。

函数式编程和命令式编程区别
1.命令式编程可读性差:别人阅读你的代码需要一段时间来理解每个语句,进而理解整个代码段的功能
2.可复用性差;
3.对模块化不是很友好;

2.函数式编程的基本内容(闭包、函数柯里化、函数组合)

2.1 函数式编程的特点

(1) 函数式是一等公民

函数是一等公民就是说:函数和其他数据类型一样,可以作为参数或者赋值给其他变量。

(2) 无状态和数据不可变

无状态,是指任何时候相同的输入的输出一定是相同的,这就要求函数内部不能依赖外部的状态 数据不可变(副作用):函数中如果想要修改函数参数对象的属性值,只能复制后修改,不能在原来的基础上修改 这两点导出和纯函数的概念。

(3) 函数式纯函数

纯函数的要求有两点:
1.无状态:不依赖于外部状态
2.无副作用:所谓的“副作用”就是指这个函数除了主要作用之外,还有其他不希望他有的作用(就好像吃头疼药主要作用是治头疼,但是还有易困的副作用)。
这里函数的主要作用是:函数本身需要输出的函数结果这个作用,副作用就是指对你输入函数参数的副作用-修改函数的参数。比如:函数的参数是一个引用对象,函数输出结果出来本来的功能外,还额外修改了输入引用参数的属性值。这个修改就是“副作用”

(4) 函数高阶应用:函数的抽象和组合--柯里化和compose组合

(5) 惰性计算:降低运行时开销

惰性计算是指函数只有在真正需要执行的时候执行。 这样做的好处主要有两个: 1.不会产生中间变量

const arr = ['john-reese', 'harold-finch', 'sameen-shaw'];
const newArr = [];
for (let i = 0, len = arr.length; i < len ; i++) {
  let name = arr[i];
  let names = name.split('-');
  let newName = [];
  for (let j = 0, naemLen = names.length; j < naemLen; j++) {
    let nameItem = names[j][0].toUpperCase() + names[j].slice(1);
    newName.push(nameItem);
  }
  newArr.push({ name : newName.join(' ') });
}
return newArr;

2.不影响业务代码的执行

const addOne = x => x + 1
const map = fn => x => fn(x)
const exec = map(addOne)

这样可以让我们在运行时创建很多基础函数,但并不影响实际业务运行速度,唯有业务代码真实调用时才产生开销。这里真正需要执行的是x+1的指令,虽然前面执行map(addOne) 只是在初始化的时候产生了开销,并不会真实执行 +1,只有真实业务代码中需要执行时候才会调用exec函数,这个时候+1才执行。

2.2 函子的概念

juejin.cn/post/684490…
www.cnblogs.com/Qooo/p/1412…
函数副作用的处理 因为有时候函数式编程中没有办法去完全避免副作用的出现,所以需要将副作用控制在一定的范围内,而控制的方式就是通过函子控制。

function double (x) { 
    return x * 2
} 
function add5 (x) {
    return x + 5 
}

我们正常去执行函数式编程的时候,会遇到连续执行好几个函数,且具有返回值作为参数的问题,一般情况下我们直接的思维是:

var x = 1;
var result = double(add5(x));

在执行函数进行最小封装的时候(拆分最小逻辑),如果在业务中遇到前后逻辑输出结果作为直接输入参数的情况下,将函数的执行放到另一个函数中的参数中是最直接的:fn2(fn1(argument))
而如果是以数据为中心进行理解的话,函数的串行执行方式无疑是更好理解,因为这种更清晰。例如:arguemnt.fn1().fn2().这种编程风格的改变需要我们制造一个中介者来实现这种串行方式。
实现方式
1.将函数作为对象中的方法:new Num(5).add().double()

class Num {
    constructor(value) {
        this.value = value
    }
    add () {
        this.value = this.value + 1;
        return new Num(this.value);
    }
    double() {
        this.value = this.value * 2;
        return new Num(this.value);
    }
}

2.通过函子实现:Functor.of(5).map(add5).map(double)
这种通过函子的方式实现,虽然不如上面看起来有纯粹的串行感觉,但是上面的缺点很明显,就是可扩展性太差的。后面如果要增加一个函数,就破坏开放封闭原则,在原有的对象中增加。但是通过同一个map来实现串行的方式也是可以理解的。

class functor { // 可以把函子理解为一个容器,这容器中很简单,就是一个value变量,还有一个map函数
    constructor(value) {
        this.value = value;
    }
    map(fn) {
        let result = fn(this.value);
        return new functor(result)
    }

}

注意:这里的map函数结构非常简单,就是先执行传入的函数参数逻辑,函数参数的参数就是从这个容器的value值拿,这个value就是上一个函数执行后的结果存在在当前这个容器中。函数参数执行的结果用作下一个new对象的value属性中。然后返回一个new 新的对象。 这样就是实现了一个functior函子。

函数柯里化、函数组合、高阶函数、函子

3.vue中为什么要采用函数式编程- composition API

vue中为什么要采用函数式编程- composition API? 目前我们的编程方式一般为面向对象编程(封装、继承、多态)。这种编程方式的缺点:

  1. 绑定关系冗长、复杂,易读性差
  2. this 的指向容易混乱,导致出错的概率大大增加

我们刚刚看到了 composition-api 在 UI 与逻辑分离上的精彩表现。但是为什么我们刚开始的面向对象就不行呢?这就要说回编程范式的问题了

我们在说到面向对象的时候,总是会想办法抽象出一个类,而类有两个最基本的概念,一个是属性,另外一个就是方法。将类实例化之后,返回一个个我们需要的对象,实例化返回的对象会继承继承所有类的属性,而对象绑定的方法本质是为了改变对象的状态。而到了我们的框架里面,状态变成了 data,方法变成了 methods, methods 和 data 强相关了,而 data 又和 我们的页面 UI 有着强绑定的关系,绑在一条船上,所以这就是为什么分不开的原因。

而 composition-api 是函数式编程的产物,函数式编程的特点就是只关心输入和输出。而函数天生就有着隔离性, 在 composition-api 的体现上就是反正我一定有一个返回值给你,对页面 UI 来说,只需要告诉它需要和哪个返回值绑定就行了。而 setup 就会处理好输出和页面 UI 的映射关系,这也就是为什么 composition-api为什么必须在 setup 里面的原因。

总结:
vue2中主要是以面向对象编程为主,对象中无非就是属性和方法,方法是为了改变对象的状态。因为vue中对象的状态对应data,方法对应method,初始化的时候每一个data都会双向绑定,这就意味着data和UI绑定,data和逻辑绑定,等价于UI和逻辑只是表面上的分离,本质上还是强绑定的。前端框架的目的之一是让UI和逻辑分离,但是vue2中这种分离的方式是基于数据的强绑定,没有真正意义上实现UI和逻辑彻底分离。
vue3中使用函数式编程,引入了composition API,通过setup函数中的reactive和ref控制,使数据要想和UI绑定,必须使用ref和reactiveAPI,否则该数据不会发生UI变化,这就相当于解除了数据和UI默认的强绑定(可以有选择的让部分数据变化不会引起UI变化)。