美文网首页
从实现一个红绿灯到函数式编程

从实现一个红绿灯到函数式编程

作者: ZuJung | 来源:发表于2018-02-22 20:06 被阅读0次

我认为函数式编程的本质是把函数当作变量来使用。最近接触了React,我们可以发现在React中处处存在函数式编程的思想,我们将JSX写成一个函数的返回值,并且在render中调用她们。函数是对于过程的抽象,我们将过程抽象成一个函数,然后根据不同的场景传入不同的变量值从而得到不同的结果。而函数式编程是对于函数的抽象,我们把函数看作是一个变量,然后根据不同的场景传入不同的函数值从而得到不同的结果。

我希望可以通过实现一个小的demo来讲清楚这件事,这个demo是我很久以前在某个技术网站看到的,具体的网址已经记不清楚了,鉴于小伙伴们对于我所讲的函数式编程的概念非常感兴趣,所以我将这个例子翻了出来,自己将它重新实现一遍。若是没有讲清楚或错误的地方,则是受限于我的浅薄的技术功底,并希望被指正。

红绿灯函数

客户希望我们实现一个红绿灯函数,每隔1秒钟,变换一次信号,无限循环。可以使用console.log来模拟信号灯亮的过程,即在控制台打印'绿灯亮',1s后继续打印'黄灯亮',1s后打印'红灯亮'...无限循环

实现这个效果非常简单,直接上代码

function semaphores() {
    setTimeout(()=>{
        console.log('绿灯亮');
        setTimeout(() => {
            console.log('黄灯亮');
            setTimeout(() => {
                console.log('红灯亮');
                semaphores();
            }, 1000)
        }, 1000)
    },1000) 
}

// delay 1s
// 绿灯亮 
// delay 1s
// 黄灯亮
// delay 1s
// 红灯亮
// delay 1s
// ...

但是很明显,这样的函数及其不优雅,我们的红绿灯只有三种颜色,如果要是有十几种颜色的霓虹灯闪来闪去的话,我们就要嵌套十几层代码了。这样可读性实在是太差了,于是我们希望可以把它优化一下。

仔细分析一下我们的代码就会发现,上面的demo有非常多的冗余代码,setTimeout在一个函数中被重复使用了三次,每次只不过是一个嵌套再打印不同的红黄绿灯而已,我们为什么不把公共部分提取出来呢?把红黄绿灯提取成变量,代码质量会好很多。

so出现了下列的代码:

const TRAFFIC_LIGHT = [
    '绿灯',
    '黄灯',
    '红灯'
]

function semaphores(lightList = [], count = 0) {
    // 控制器
    let lightLength = lightList.length;
    
    return setTimeout(() => {
        console.log(`${lightList[count % lightLength]}`);
        count ++;
        semaphores(lightList,count);
    }, 1000)
}

// delay 1s
// 绿灯亮 
// delay 1s
// 黄灯亮
// delay 1s
// 红灯亮
// delay 1s
// ...

我们还可以进一步优化,同时将时间抽离:

const TRAFFIC_LIGHT = [
    ['绿灯', 1000],
    ['黄灯', 2000],
    ['红灯', 3000]
]

function semaphores(lightList = [], count = 0) {
    const lightLength = lightList.length;     
    
    return function handleSemaphores(){
        const [light, time] = lightList[count % lightLength];
              
        return setTimeout(() => {
            console.log(`${light}亮`);
            count ++;
            handleSemaphores();
        }, time)
    }
}

// delay 1s
// 绿灯亮 
// delay 2s
// 黄灯亮
// delay 3s
// 红灯亮
// delay 1s
// ...

我们可以更加容易修改我们的代码,以应对将来可能的需求变更。这也是我们常见的函数形式。变量只是 Number、String、Object、undefined、null、Boolean,但是我们再次将问题变得复杂一些:

我们的红绿灯效果良好,客户非常满意,并且希望扩展应用范围。为了应对可能到来的困惑,我们需要在每次信号灯亮起的时候添加上一条提示语,提醒剩余时间。不同的应用场景将有不同的提示语。

这也非常简单,我们只需要多加一条语句就可以完成:

const TRAFFIC_LIGHT = [
    ['绿灯', 1000],
    ['黄灯', 2000],
    ['红灯', 3000]
]

function semaphores(lightList = [], count = 0) {
    const lightLength = lightList.length;     
    
    return function handleSemaphores(){
        const [light, time] = lightList[count % lightLength];
              
        return setTimeout(() => {
            console.log(`${light}亮`);
            // add here!!!
            console.log('这是一条提示语');
            count ++;
            handleSemaphores();
        }, time)
    }
}

// delay 1s
// 绿灯亮 
// 这是一条提示语
// delay 2s
// 黄灯亮
// 这是一条提示语
// delay 3s
// 红灯亮
// 这是一条提示语
// delay 1s
// ...

但随着我们的应用场景进一步增多,我们的红绿灯将广泛的用于医疗、运输、零售行业,对于这些行业我们需要在信号灯亮起时拥有不同的操作,有的是发出声响、有的是打印提示语、有的是发出警报、有的是打开开关...

那么我们是不是需要把上面的那份代码到处拷贝一下,然后修改位于16行的代码,分别把它修改为发声、打印、报警、开关控制...

显然一般的函数已经无法满足我们的需求了,这时候我们就需要函数式编程。

函数式编程

我上面只是为了引出函数式编程的例子,所以举例夸张了一些。事实上函数式编程并不是非常高大上的概念,它就和面向对象、面向过程一样,只是一种编程的范式,在实际中拥有着非常广泛的应用(例如JSX)

就像我一开始提到的那样,函数式编程的核心不过是将函数当作变量那样来使用。我们希望改造一下我们的红绿灯函数,使我们的函数在信号灯亮后,可以在不同的场景使用不同的参数,我们来设计一下这个函数.首先我们需要传入一个函数,所以我们在形参列表中加入一个handler的变量,便于我们使用它。然后在我们希望使用它的地方使用就好了。

const TRAFFIC_LIGHT = [
    ['绿灯', 1000],
    ['黄灯', 2000],
    ['红灯', 3000]
]

// 请注意我们在这里加入了一个参数handler
function semaphores(lightList = [], handler, count = 0) {
    const lightLength = lightList.length;     
    
    return function handleSemaphores(){
        const [light, time] = lightList[count % lightLength];
              
        return setTimeout(() => {
            console.log(`${light}亮`);
            // 在这里使用它
            handler && handler(light, time);
            count ++;
            handleSemaphores();
        }, time)
    }
}

我们可以这样使用上面的函数:

// 我们只需要在不同的场景改变不同的handler就可以了
const handler = function (light, time) {
    console.log('函数式编程好爽啊');
    console.log(`${light}亮${time}毫秒~~`)
}

const doTrafficLight = semaphores(TRAFFIC_LIGHT, handler);
const trafficTimeHandler = doTrafficLight();
// delay 1s
// 绿灯亮
// 函数式编程好爽啊
// 绿灯亮1000毫秒~~
// delay 2s
// 黄灯亮
// 函数式编程好爽啊
// 黄灯亮2000毫秒~~
// delay 3s
// 红灯亮
// 函数式编程好爽啊
// 红灯亮3000毫秒~~
// ...

我们更可以优化一下上面的函数,使得不同等亮起时使用不同的行为函数:

const TRAFFIC_LIGHT = [
    ['绿灯', 1000, function() {
     // do something...
    }],
    ['黄灯', 2000, function() {
     // do something...
    }],
    ['红灯', 3000, function() {
     // do something...
    }]
]

// 我们去掉了handler!!!!
function semaphores(lightList = [], count = 0) {
    const lightLength = lightList.length;     
    
    return function handleSemaphores(){
        const [light, time, handler] = lightList[count % lightLength];
              
        return setTimeout(() => {
            console.log(`${light}亮`);
            // 在这里使用它
            handler && handler(light, time);
            count ++;
            handleSemaphores();
        }, time)
    }
}

// delay 1s
// 绿灯亮
// dosomething1...
// delay 2s
// 黄灯亮
// dosomething2...
// delay 3s
// 红灯亮
// dosomething3...
// ...

函数式编程的抽象程度更高,它是对于过程的抽象。如果没有传入的参数作为支撑,那么这个函数毫无意义,比较明显的例子是JavaScript中的mapreduce。这是最主要的概念,剩下的概念则都是一些规定,帮助我们写出更好的更健壮的函数式函数,相信理解了我刚刚所说的例子,再去理解其他概念会容易许多。

相关文章

  • 函数式编程从零到一

    从零到一:很纯的函数式 从干活的角度看待函数式编程和一般的编程方法 函数addOne是一个函数式编程的写法 函数a...

  • 从实现一个红绿灯到函数式编程

    我认为函数式编程的本质是把函数当作变量来使用。最近接触了React,我们可以发现在React中处处存在函数式编程的...

  • 从点滴基础探究Kotlin的独特魅力

    0. 序言 从接触Rxjava了解到函数式编程,从了解函数式编程想起Lambda表达式,从Lambda表达式接触到...

  • 一:函数式编程:

    函数式与命令式编程的区别: 命令式编程关注的是怎么做,函数式编程关注的是做什么(由系统选择如何实现),命令式编程:...

  • 向量化

    python向量化本身做得不是很好需要借助函数式编程或者列表推导式实现 1 列表推导式 2 函数式编程

  • iOS链式编程及函数式编程

    提到链式编程和函数式编程,最典型的代表是Masonry 比较完美的实现了函数式编程和链式编程。例如 ``` [vi...

  • Java lambda表达式

    1. Java函数式接口 Java实现函数式编程的方式是函数式接口(functional interface),函...

  • 函数式编程(一) lambda、FunctionalInterf

    由于函数式编程涉及内容较多,因此对函数式编程写一个系列博客,内容从JAVA8的新特性开始阐述,而后阐述函数式编程的...

  • RxSwift初探(1)

    一、前提:函数响应式编程思想 简单来说 函数响应式编程 = 函数式编程 + 响应式编程 (1)函数式 函数式编程是...

  • js函数式编程最佳实践 - 持续更新

    函数式编程最佳实践 学习文档 函数式编程术语 数组字串处理 创建 tags 创建表格 实现一个展示/收起功能 倾向...

网友评论

      本文标题:从实现一个红绿灯到函数式编程

      本文链接:https://www.haomeiwen.com/subject/dziztftx.html