函数式编程:
1. 函数式编程,函数是JS中第一公民,将函数作为参数,作为返回值,在函数之间相互传递,函数变得越来越重要,这种编程就是函数式编程。
2. 函数式编程:一种编程范式(一种规范或方式)。
纯函数也是函数式编程中非常重要的一个概念,纯函数的定义:
- 确定的输入,一定会产生确定的输出
- 函数在执行过程中,不能产生副作用;
那么这里又有一个概念,叫做副作用,什么又是副作用呢?
- 副作用(side effect)其实本身是医学的一个概念,比如我们经常说吃什么要本来是为了治病,可能会产生一些其他的副作用;
- 在计算机科学中,也引用了副作用的概念,表示在执行一个函数时,除了返回函数数值之外,还对调用函数产生了附件的影响,
比如修改了全局变量,修改参数或者改变外部的存储;
纯函数在执行的过程中就是不能产生这样的副作用:
- 副作用往往是产生bug的 “温床”
理解JavaScript纯函数的作用:
- 在react开发中纯函数是被多次提及的;
- 在react中组件就被要求像是一个纯函数(为什么是像,因为还有class组件), redux中共有一个reducer的概念,也是要求必须是一个纯函数;
- 所以掌握纯函数对于理解很多框架的设计是非常有帮助的;
纯函数的优势:
- 因为你可以安心的编写和安心的使用;
- 你在写的时候保证了函数的纯度,只是单纯实现自己的业务逻辑即可,不需要关系传入的内容是如何获取的或者依赖其他的外部变量是否已经发生修改了;
- 你在用的时候,你确定你的输入内容不会被任意篡改,并且自己确定的输入,一定会有确定的输出;
01.数组的两个函数对比
var names = ['abc', 'cba', 'nba', 'dna'];
// slice只要给它传入一个start / end, 那么对于同一个数组来说,它会给我们返回确定的值。
// slice函数本身它是不会修改原来的数组
// slice -> this
// clice函数本身就是一个纯函数
// var newNames = names.slice(0, 3);
// console.log(newNames);
// console.log(names);
// ['abc', 'cba', 'nba', 'dna']
// splice在执行时,有修改掉调用的数组对象本身,修改的这个操作就是产生的副作用
// splice不是一个纯函数
var newNames2 = names.splice(2);
console.log(newNames2);
console.log(names);
02.纯函数的练习
// foo是否是一个纯函数?
// 1.相同的输入一定产生相同的输出
// 2.在执行的过程中不会产生任何的副作用
function foo(num1, num2) {
return num1 * 2 + num2 * num2;
}
// bar不是一个纯函数,因为它修改了外界的变量
var name = 'abc';
function bar() {
console.log('bar其他的代码执行');
name = 'cba';
}
bar();
console.log(name);
// baz也不是一个纯函数,因为修改了传入的参数
function baz(info) {
info.age = 100;
}
var obj = { name: 'why', age: 18 };
baz(obj);
console.log(obj);
// test是否是一个纯函数,是一个纯函数
function test(info) {
return {
...info,
age: 100
}
}
test(obj)
test(obj)
test(obj)
test(obj)
// React的函数组件(类组件)
function HelloWord(props) {
// 在vue里面也是不允许这样操作,它违反了单向数据流
props.info = {};
props.info.name = 'why'
}
// reducer里面就是这样的
var info = {};
function foo(obj) {
return {
...obj,
name: 'why'
}
}
info = foo(info);
console.log('info=', info);
function foo(m, n, x, y) {
return m + n + x + y
}
foo(10, 20, 30, 40)
纯函数的总结:
- 纯函数就要求我们不能随便修改传入的参数,也不能随便修改全局的东西,也不能随便乱输出东西
- 只需关心这个函数的参数和返回值就可以了
03.柯里化的过程和结构
// 柯里化也是属于函数式编程里面一个非常重要的概念。
// 我们先来看一下维基百科的解释:
// - 在计算机科学中,柯里化(英语:Curring), 又译为卡瑞化和加里化;
// - 是把接收多个参数的函数,变成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数,
// 而且返回结果的新函数的技术;
// - 柯里化声称:“如果你固定某些参数,你将得到接受余下参数的一个函数”
// 维基百科的解释非常的抽象,简单在这里做一个总结:
// - 值传递给函数一部分参数来调用它,让他返回一个函数去处理剩余的参数;
// - 这个过程就称之为柯里化
// 只要把传入的参数拆分变成多个函数的调用,就是柯里化的过程
function foo(m, n, x, y) {
return m + n + x + y
}
foo(10, 20, 30, 40)
// // 下面代码是柯里化过程
function bar(m) {
return function (n) {
return function (x) {
return function (y) {
return m + n + x + y
}
}
}
}
bar(10)(20)(30)(40)
function add(x, y, z) {
return x + y + z;
}
var result = add(10, 20, 30)
console.log(result);
function sum(x) {
return function (y) {
return function (z) {
return x + y + z;
}
}
}
var result1 = sum(10)(20)(30);
console.log(result1);
var sum2 = x => y => z => {
return x + y + z;
}
console.log(sum2(10)(20)(30));
// var sum3 = x => {
// return y => {
// return z => {
// return x + y + z;
// }
// }
// }
var sum3 = x => y => z => x + y + z;
console.log(sum3(10)(20)(30));
04_柯里化-单一职责的原则
// 单一职责原则(SRP single responsibility principle)
// 面向对象 -> 类 -> 尽量完成的单一的一件事
// 那么我们为什么需要有柯里化?
// - 在函数式编程中,我们其实往往希望一个函数处理的问题尽可能的单一,而不是将一大堆的处理过程交给一个函数来处理
// - 那么我们是否就可以将每次传入的参数在单一的函数中进行处理,处理完成后在下一个函数中再使用处理后的结果;
function add(x, y, z) {
x = x + 2;
y = y * 2;
z = z * z;
return x + y + z;
}
console.log(add(10, 20, 30));
function sum(x) {
x = x + 2;
return function (y) {
y = y * 2;
return function (z) {
z = z * z;
return x + y + z;
}
}
}
console.log(sum(10)(20)(30));