欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript函数式编程(2)

程序员文章站 2022-03-22 10:08:57
函数式编程主要是利用函数等特性,即给一个确定的输入总能保证相同的输出,函数只做一件事情等等,让代码看起来更简短且维护性更高(但很容易出现反效果导致被喷)。上一篇文章主要介绍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,如下图

JavaScript函数式编程(2)

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

 

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

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

或者以下这种

JavaScript函数式编程(2)

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

 

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

 

  • 把所有 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