lecture-1-编程范式与纯函数
编程范式类型
命名式编程
命令式编程是面向一个过程的思维模式,关注的是想要达到目的所需要的一系列具体的执行步骤
举个例子:番茄炒蛋,对于命名式编程来说,他在意的是番茄炒蛋的步骤,设定一系列的指令步骤,一步一步执行得到番茄炒蛋
面向对象编程
面向对象编程会把事物抽象成对象的概念,关注的是这个问题里面有哪些对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法,问题得到解决。
举个例子:番茄炒蛋,对于面向对象编程来说,主要是以功能来划分对象,例两个对象:人拥有一些方法:洗番茄、切、炒,锅拥有一些方法:烹饪,然后用对象执行方法的方式来解决问题
函数式编程
函数式编程不在乎过程,只在乎结果,只在乎输入与输出,相比于命令式编程,有更强的可读性和代码维护性以及功能扩展性
举个例子;番茄炒蛋,对于函数式编程来说,无论你是准备原材料让人做给你吃,还是准备足够的钱买一份吃。都得到了一份番茄炒蛋,过程就像一个黑盒,并不关注,只需要关注我需要提供什么(输入),我能够得到什么(输出)
我们可以也对每一个黑盒进行拆分,例如一道流水线(大黑盒),需要经过A、B、C三个环节,那么A环节我可以认为是一个黑盒,我只需要知道A环节需要什么,产出是什么,同理B、C,并不关心每个环节的具体执行细节,只需将3个函数进行组装到一起即可
函数式编程基石-纯函数(函数式编程的第一特征)
纯函数是什么
输入输出数据流全是显式的函数。
- 对于相同的输入(函数的入参),总是会得到相同的输出(函数的返回值)
- 在执行过程中没有语义上可观察的副作用
副作用是什么
副作用指的是在执行一个函数的过程中,对执行的上下文或者外部环境造成了一些其他的影响,这个影响就是副作用
举个例子:对于治疗A类系统疾病,我们服用了A药物,但是A药物除了治疗A类疾病,会对B类系统造成影响,这时候就存在副作
如何知道一个函数是否是纯函数
对于函数是否是一个纯函数,不能仅仅看函数本身
例如
const a = 10;
const b = 20;
const add=()=>{
return a + b;
}
对于add函数来说,他的输入就是入参,入参在这里一直是void,但是得到的结果却受作用域外的a、b影响,这实际上是违背了纯函数定义的第一条,并且同时他更加违背了纯函数的定义
再看改造之后的
const add=(a:number,b:number)=>{
return a + b;
}
这样就符合纯函数的两个条件了,对于add函数来说,对于同样的输入,得到的永远都是同样的输出,对于add函数除了做加法之外没有任何超出作用域之外的影响
再看这样一个例子
const add=(a:number,b:number)=>{
console.log(a,b);
return a + b;
}
这其实也不是一个纯函数,因为console其实对外界产生了影响,比如你的控制台会打印a、b的值
再看这样一个例子
const getData = async ()=> {
const {data} = await GET();//注意:GET表示一个网络请求
return data;
}
对于引入了网络请求的函数来说,他是不纯的,因为网络请求会受很多因素影响,导致每次执行都可能会获取到不同的输出
纯函数的本质
纯函数的本质就在他的定义中,纯函数要求输入输出的数据流全是显式的(只有横向数据传输,可以类比为流水线)
显式指的是数据的来源(入参)以及出口(返回值),换句话说,纯函数要求数据以入参的形式传入(显式输入数据流),返回值的形式返回(显式输出数据流),这就意味着函数除了入参和返回值之前,不以任何其他形式与外界进行数据交换,在换句话说:除开函数作用域自己本身声明的变量,其他的变量只能来自于入参
这时候再反过来看上面的add
例子,就变得比较容易判断了,它存在隐式数据流(a、b)输入,而第二个例子,则是存在隐式数据流输出
纯函数的意义
纯函数除了纯纯的计算,应该不具有其他的作用,不纯的函数最大的两个问题就算他具有不确定性以及副作用,他无法像数学中的函数那样,给定一个输入,会得到一个准确的输出,而是存在着变化的可能
此外,纯函数会更具灵活性,他不会受任何上下文环境影响,在任何上下文中都应该是成立的,以便于我们不用去关注计算逻辑之外的任何外部影响,纯函数强调的便是计算与副作用分离
副作用
对于纯函数来说,副作用无疑是最难受的,但是对于一整个程序来说,副作用却是至关重要的,函数生产的是数据,这些数据要想作用于外部世界、创造一些真正的改变,就必须借助副作用
因为要做网页,这需要程序员操作DOM;因为要 CRUD,这需要程序员操作DB;因为要读写文件,这需要程序员执行 IO…… 如果我们试图把一个业务程序员的简历用一句话概括,那无外乎“精通实现各种副作用”。
老板和客户不会关心你的代码是否优雅,只会关心那些肉眼可见的副作用——页面渲染、网络请求、数据读写等等是否符合预期。
会关注代码本身的,有且仅有我们程序员自己,这句话也透露出一丝无奈吧,当程序员本身只想为了完成任务而完成任务,不管设计,不管拆分,不管功能扩展性,很多东西都会变得没有意义了。。。
总结
纯函数是函数式编程的一个最大的前提,也是这坨知识体系的根基。纯函数的这些规则并不是为了约束而约束,而是为了追求更高的确定性;同时引导我们做更加合理的逻辑分层,写出更加清晰、更善于应对变化的代码