JavaScript函数式编程(2)
程序员文章站
2022-06-28 19:15:25
函数式编程主要是利用函数等特性,即给一个确定的输入总能保证相同的输出,函数只做一件事情等等,让代码看起来更简短且维护性更高(但很容易出现反效果导致被喷)。上一篇文章主要介绍js中 map/filter/reduce/sort/some等js数组操作方法。我在最初接触函数式编程时,也感到很疑惑,函数式编程和这几个ES的API方法有啥关系,直到最近跳槽,公司内以为前端技术专家反复强调 一般情况不允许直接修改变量,尤其是一些数组和对象,尽可能不要使用深拷贝;主要有以下原因防止拷贝后的对象会.....
函数式编程主要是利用函数等特性,即给一个确定的输入总能保证相同的输出,函数只做一件事情等等,让代码看起来更简短且维护性更高(但很容易出现反效果导致被喷)。
上一篇文章主要介绍js中 map/filter/reduce/sort/some等js数组操作方法。
我在最初接触函数式编程时,也感到很疑惑,函数式编程和这几个ES的API方法有啥关系,直到最近跳槽,公司内一位前端技术专家反复强调 一般情况不允许直接修改变量,尤其是一些数组和对象,尽可能不要使用深拷贝;主要有以下原因
- 防止拷贝后的对象会出现丢失原型链上的方法;
- 修改是万恶之源,可以做一个统计,有相当多的bug是因为变量修改过程导致的,这也是ES6推出const这种定义变量类型的深层次原因
以上说法在当时不理解直到后来大量使用loadsh ,一个封装了很多js工具函数库。你在使用这个库时需要特别注意 该方法是否会修改原变量。
为了保证尽可能不直接修改变量这一基本原则
- 需要更新修改对象使用
Object.assign
- 数组和对象的拷贝拓展运算符
...
- 数组合并最好使用concat
以下是举例子
function NewObj(a,b){
this.a = a;
this.b = b;
this.objfn = ()=>{
console.log('NewObj1-del')
};
}
function NewObj2(b){
this.b = b;
this.objfn2 = ()=>{
console.log('NewObj2-add')
};
}
var obj = new NewObj(1,2)
var obj2 = new NewObj2(3)
//期望在函数中将obj中的b改为obj2中的值且 增加一个值{c:2}
function fn1(obj,obj2){
obj.b = obj2.b;
obj.c = 2;
return obj
}
// 使用以下方式
function fn2(obj,obj2){
return Object.assign(obj2,obj,{c:2})
}
// 或者是以下
function fn3(obj,obj2){
return {...obj,...obj2,c:2};
}
我希望fn1/fn2函数能够实现将obj中的b改为obj2中的值且 增加一个值{c:2}
- 运行fn1 fn2 fn3 发现 fn1 丢掉了 objfn2,如下图
从上面例子也能看出,不可以直接修改变量的重要性
下面是典型的函数式编程和命令式编程
函数式编程:
var reformatDate = function(date) {
const month = {
"Jan":'01',
"Feb":'02',
"Mar":'03',
"Apr":'04',
"May":'05',
"Jun":'06',
"Jul":'07',
"Aug":'08',
"Sep":'09',
"Oct":'10',
"Nov":'11',
"Dec":'12'
}
return date.split(" ").map((v,index)=>{
const value = v.replace(/[^0-9]/ig,"");
if(index === 0 && value.length<2){
return '0' + value;
}else if(index === 1){
return month[v]
}else{
return value;
}
}).reverse().join('-');
};
命令式编程
var reformatDate = function(date) {
let outPut = date.split(' ')
let day = ''
if(outPut[0].length == 4) {
day = outPut[0].substring(0,2)
} else {
day = '0' + outPut[0].substring(0,1)
}
let month = ''
let year = outPut[2]
switch(outPut[1]) {
case 'Jan':
month = '01'
break
case 'Feb':
month = '02'
break
case 'Mar':
month = '03'
break
case 'Apr':
month = '04'
break
case 'May':
month = '05'
break
case 'Jun':
month = '06'
break
case 'Jul':
month = '07'
break
case 'Aug':
month = '08'
break
case 'Sep':
month = '09'
break
case 'Oct':
month = '10'
break
case 'Nov':
month = '11'
break
case 'Dec':
month = '12'
break
}
return `${year}-${month}-${day}`
};
或者以下这种
以上代码尽可能不修改原数据,尽可能使用链式调用,尽可能不产生多余变量,某些方面也增加了代码维护难度,但是如果始终遵循,函数的单一职责,并保持细粒度以及一些严格的函数规范,比如参数/命名,会让后期的维护变得更简单。
以下是总结一些短句技巧,适合刚入门的函数式编程练习
- 把所有 for 循环都换成尾递归或 forEach。不希望看到for循环,尽可能使用map/filter/reduce/sort/some 等高阶函数
- 把所有 add(1, 2, 3) 都换成 add(1)(2)(3)。
- 把所有 if else 都换成 switchMap。
- 把所有 callback 都包成 Monad。
- 把所有 class 都换成函数闭包。
- 把所有 class 组件都换成 function 组件。
- 把所有 JSON 都装进 ImmutableJS。
- 把所有 Math.max(...list) 都换成 list.reduce。
- 把所有数据转换操作都重构成 parser combinator。
- 把所有命令式 Web API(如 Canvas 和 WebGL)都 polyfill 成 noop。
- 把所有带 mutation 的 let 都换成 const。(并不希望在你但代码中看到var/let)
- 把所有注释里的「命令式」和「面向对象」字样都删掉。
- 尽最大可能节省变量(可以利用loadsh+链式调用)
- 尽可能保证不要二次修改变量
本文地址:https://blog.csdn.net/qq_16546829/article/details/107308915