记录一下前端学习笔记,坚持打卡记录!!
开始第四篇
函数式编程的出现
首先看一个题目:需要将数组 ['progressive%coding','functional$%coding']转化为数组[{name: 'Progressive Coding'}, {name: 'Objective Coding'}, {name: 'Functional Coding'}],通常我们会按照以下的方式处理:
const arr: string[] = ['progressive$%coding', 'objective$%coding', 'functional$%coding']
const changeArr = (arr) => {
let res: object[] = []
arr.forEach(element => {
const eleArr = element.split('$%')
let str: string[] = []
eleArr.forEach(name => {
let nameItem = name[0].toUpperCase() + name.slice(1);
str.push(nameItem);
})
res.push({
name: str.join(' ')
})
});
return res
}
console.log(changeArr(arr))
正常这样处理是没有太多问题的,也是我们写业务时常用的方式,但是也存在一些问题
- 过程逻辑复杂,需要看完整段才知道内容,不好维护,可读性较差
- 存在临时变量,并且整体段落首尾封闭,迭代扩展难度高
如果用下面的方法,则会解决上述问题
const arr2: string[] = ['progressive$%coding', 'objective$%coding', 'functional$%coding'];
// 1.将字符串的首字母转化为大写
const capitalizeFirstLetter = (str: string): string => {
return str[0].toUpperCase() + str.slice(1)
}
// 2.字符串按照分割符分割并且组长
const splitAndCapitalizeAndJoin = (str: string): string => {
const parts = str.split('$%')
return parts.map(capitalizeFirstLetter).join(' ')
}
// 3.组装一个对象,其中包含一个指定的键和值
const assembleObj = (key: string, value: any): { [key: string]: any } => {
return { [key]: value };
};
// 转换整个数组
const changeArr = (arr: string[]): object[] => {
return arr.map(element => {
const capitalizedString = splitAndCapitalizeAndJoin(element);
return assembleObj('name', capitalizedString);
});
};
console.log(changeArr(arr2));
现在,每个函数都专注于执行一个具体的任务,这有助于提高代码的可读性和可维护性。同时,这也使得每个函数都更容易进行单元测试,因为它们的功能更加明确。
函数式编程原理特点
理论思想
- 函数作为一等公民,逻辑功能实现最终落脚点都是函数,函数实现+拼接流程
- 惰性执行 - 衔接型,性能节约
// 惰性函数
const program = name => {
if (name === 'progressive') {
return program = () => {
console.log('this is progressive');
}
} else if (name === 'objective') {
return program = () => {
console.log('this is objective');
}
} else {
return program = () => {
console.log('this is functional');
}
}
}
program('progressive')();
- 无状态 - 幂等;输入相同,结果相同;不会因为外界的调用而改变能力功能
- 无副作用;函数的内部不应该直接对整个系统中任何参数变量进行改动
实际开发
一些纯函数以及不满足纯函数特性例子
const _class = {
name: 'objective'
}
// 函数内部引入了外部变量 —— 不符合无状态
const score = str => _class.name + ':' + str;
// 直接修改了输入参数 —— 有副作用
const changeClass = (obj, name) => obj.name = name;
// #####################
const _class = {
name: 'objective'
}
const score = (obj, str) => obj.name + ':' + str; // 不依赖外部变量
const changeClass = (obj, name) => ({...obj, name}); // 未修改外部变量
changeClass(_class, 'functional');
score(_class, 'good');
手写构造可拆分传参的累加函数
实现add(1)(2)(3)(4)
// 定义一个柯里化累加函数 add
const add = function () {
// 将函数的参数转换为数组并存储在 args 中
let args = Array.from(arguments);
// 定义一个内部函数 inner,用于累加参数
let inner = function () {
args.push(...arguments); // arguments默认为函数的传入参数
return inner;
}
// 给 inner 函数添加一个 toString 方法,用于计算和返回累加结果
inner.toString = function () {
return args.reduce((prev, cur) => (prev + cur))
}
return inner;
}
console.log(add(1)(2)(3)(4).toString())
组装函数思想
const compose = (f, g) => x => f(g(x))
const sum1 = x => x + 1;
const sum2 = x => x + 2;
const sum12 = compose(sum1, sum2);
console.log(sum12(1));