JavaScript函数式编程(2) - Go语言中文社区

JavaScript函数式编程(2)


函数式编程主要是利用函数等特性,即给一个确定的输入总能保证相同的输出,函数只做一件事情等等,让代码看起来更简短且维护性更高(但很容易出现反效果导致被喷)。

 

上一篇文章主要介绍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,如下图

image.png

从上面例子也能看出,不可以直接修改变量的重要性

 

下面是典型的函数式编程和命令式编程

leetcode仅含 1 的子串数

函数式编程:

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}`
};

或者以下这种

image.png

以上代码尽可能不修改原数据,尽可能使用链式调用,尽可能不产生多余变量,某些方面也增加了代码维护难度,但是如果始终遵循,函数的单一职责,并保持细粒度以及一些严格的函数规范,比如参数/命名,会让后期的维护变得更简单。

 

以下是总结一些短句技巧,适合刚入门的函数式编程练习

 

  • 把所有 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+链式调用)
  • 尽可能保证不要二次修改变量

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_16546829/article/details/107308915
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-31 04:44:31
  • 阅读 ( 770 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢