1.命令式:一个函数中会把具体细节展现出来
2.声明式:把具体细节隐藏,只描述了做了什么
函数式的风格中的核心概念:不可变性、纯函数、数据转换、高阶函数、递归
不可变性:

let list = [{title:'Rad red'},{title:'Lawn}];
const addColor1 = (title,color)=>{
list.push({title,color})
return Array
}
const addColor2 =(title,color)=>[...list,{title,color}]
addColor2保持了数据的不变性,使外部list没有被修改
View Code
纯函数:基于参数做计算,并返回一个值的函数
纯函数至少接受一个参数,而且始终返回一个值或者另一个函数。这种函数没有副作用,不会设置全局变量,也不更改应用的状态。纯函数把数据视为不可变数据。

const frederick = {
name:'React学习手册',
canRead:false,
canWrite:false
}
const foo1=() ={
frederick.canRead = true;
rederick.canWrite = true;
}
const foo2 =(book)=> {
book.canRead = true;
book.canWrite = true;
return book
}
此时,foo1有副作用:没有参数,没有返回值,更改了全局变量;foo2则是一个纯函数,没有更改外部变量
View Code
数据转换:如果数据都是不可变的,信息再一个应用中如何流动呢?再函数式编程中,数据从一种格式编程另一种格式。我们要做的就是使用转换后的副本。
map

map
const schools= {
学校1:1,
学校2:2,
学校3:3
}
const transformSchoolObjToschoolList = (school)=>Object.keys(schools).map(
schoolName=>({schoolName:school[schoolName]})) // 将学校对象改成学校数组
const editName = (oldName,name,arr)=>
arr.map(itme=>(item.name===oldName ? {...itme.name}:item)
// 更新学校名称
View Code
reduce

reduce函数可以把数组转换成任何值,包括数字、字符串、布尔值、对象、甚至是函数。
const ages = [11, 43, 52, 72, 31, 23, 42, 62, 21, 13];
const maxValue= ages.reduce(
(initValue, age) => (age > initValue ? age : initValue),
0
);
console.log("maxValue", maxValue); //72 找出最大值
const obj1 = colors.reduce((initValue, color) => {
initValue[color["id"]] = { ...color };
return initValue;
}, {});
console.log(obj1); // 数组对象根据id转换为对象
const obj2 = colors.reduce((initValue,{id , title, rating}) => {
initValue['id'] = { title,rating};
return initValue;
}, {});
console.log(obj1); // 数组对象根据id转换为对象-简便写法
const uniqList = colorList.reduce(
(list, color) => (!list?.includes(color) ? [...list, color] : list),
[]
);
console.log("uniqList: ", uniqList);//不重复数组
View Code
高阶函数:用于处理其它函数为参数的函数。,其参数可以是函数,也可以返回函数,或者两者同时有。
Array.map/Array.filter/Array.reduce都是高阶函数
递归:创建着重调用自身的函数。

//倒计时
const countDown = (value, fn) => {
fn(value);
return value > 0 ? countDown(value - 1, fn) : value;
};
countDown(10, (value) => console.log(value));
const countDown1 = (value, fn, delay = 1000) => {
return value > 0
? setTimeout(() => {
fn(value);
countDown1(value - 1, fn);
}, delay)
: value;
};
countDown1(10, (value) => console.log(value));
// 从对象里根据路径取某个属性
const Dan = {
type: "person",
data: {
gender: "male",
info: {
id: 22,
fullname: {
first: "Dan",
last: "Deacon",
},
},
},
};
const deepPick1 = (fields, object = {}) => {
const [first, ...reaming] = fields.split(".");
return reaming.length
? deepPick(reaming.join("."), object[first])
: object[first];
};
// console.log("102-", deepPick1("data.info.fullname.first", Dan));
// 对象指定属性填加一个值
const deepPick2 = (fields, object = {}) => {
const [first, ...reaming] = fields.split(".");
return reaming.length
? {
...object,
[first]: deepPick2(reaming.join("."), object[first]),
}
: { ...object, [first]: object[first], name: "19999" };
};
// console.log("102-", deepPick2("data.info.fullname.first", Dan));
// 对对象里的某些属性进行加工,比如在嵌套的时候对整个对象里的日期进行格式化有用
const getObjByWrapFieldsList2 = (list, object) =>
list?.reduce((obj, item) => {
if (item in object) {
obj[item] = object[item] + "我被修改了";
}
return obj;
}, {});
const deepPick4 = (fields, object = {}, wrapFields) => {
const [first, ...reaming] = fields.split(".");
const obj = getObjByWrapFieldsList(wrapFields, object);
return reaming.length
? {
...object,
[first]: deepPick4(reaming.join("."), object[first], wrapFields),
...obj,
}
: { ...object, ...obj };
};
console.log(
"102-",
deepPick4("data.info.fullname.first", Dan, ["type", "id"])
);
View Code
compose:把函数组合在一起

const compose = (...fns)=> args=> fns.reduce((compose,fn)=>fn(compose),args) // 这个里面reduce的初始值是参数,后面每次返回一个传入参数的函数的运算结果
View Code
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/278827.html