JavaScript与函数式编程

JavaScript与函数式编程

绝大多数编程语言都会有函数的概念(或者说所有的?我不太确定),他们都可以做出类似的操作:

function(x) {
  return x * x
}

但是Javascript更适合函数式编程,因为函数对于js来说,是一等公民

我们可以把匿名函数赋值给一个变量,比如:

let pow = function(x) {
  return x * x
}

然后我们可以将这个函数赋值给另一个变量:

let comeon = pow
comeon(x)

这样做和直接调用pow(x)是一样的效果。

甚至于我们可以将函数作为参数传入另一个函数,这样,诸多小函数可以汇聚在一起,变得异常强大!

filter()

OK,我们接下来看一些比较基础的例子。

首先是filter(),这是我最喜欢的函数之一。filter()方法会创建一个新的数组,并且我们可以传入一个判断函数,将符合条件的元素,放入新的数组。

现在我们有一个数组,里面存放了很多游戏,每个元素都记录了该游戏需要花多少钱:

let games = [
  {
    name: '英雄联盟',
    cost: 45
  },
  {
    name: '穿越火线',
    cost: 888
  },
  {
    name: '魔兽世界',
    cost: 75
  },
  {
    name: '征途',
    cost: 1000000
  }
]

然后我们需要找出,花费不超过一百元的游戏,该怎么做呢?

可能是这样:

let target = []
for(let i = 0; i < games.length; i++) {
  if(games[i].cost <= 100) {
    target.push(games[i])
  }
}

这是大家从大学开始学C语言的时候就会用的方法。但是我现在想用filter()方法重写它:

let target = games.filter((game) => {
  return game.cost <= 100
})

Wow! Awesome!

我稍微解释一下,防止有同学没有看懂,这里传入了一个函数,函数接收了一个参数,这个参数就是games的每一个元素依次传入的值,在每一次传入之后,我们都返回一个逻辑值,这个逻辑值取决于该游戏cost是否小于100,如果返回了true该元素就会被放到新的数组里去,反之同理。

注意:

  • filter()不会对空数组进行检测
  • filter()不会改变原始数组

实际上,filter内部的处理方法可能和我们使用for循环一模一样!但是我们利用函数式编程,写了更少的代码、更少的逻辑。Less code! Less time! Less bug!

这就是函数式编程的美妙之处。

map()

我们现在先看回之前写的数组:

let games = [
  {
    name: '英雄联盟',
    cost: 45
  },
  {
    name: '穿越火线',
    cost: 888
  },
  {
    name: '魔兽世界',
    cost: 75
  },
  {
    name: '征途',
    cost: 1000000
  }
]

现在我们要把每一款游戏的名字都拿出来,组成一个新的数组。

这种操作是非常常见的,比如我们使用React,向服务器请求了JSON数据,接下来需要在这里渲染名字,那里渲染价格……等等。

let gameName = games.map((item) => {
  return item.name
})

我们甚至可以做出更多的骚操作,比如说:

let gameName = games.map((item) => {
  return `${item.name}是一个${item.cost > 100? '坑钱游戏':'良心游戏'}`
})

得到结果["英雄联盟是一个良心游戏", "穿越火线是一个坑钱游戏", "魔兽世界是一个良心游戏", "征途是一个坑钱游戏"]

Wow! Awesome! 只能用优雅两个字来形容!

reduce()

reduce()单词本身是减少的意思,但是实际上你可以将reduce()理解为求和(事实并不如此,reduce更加强大且灵活,但是此时可以暂时这么理解,更多特性可以在下一节看到)。

语言太过苍白无力,我们来看看代码:

let numbers = [1, 2, 3, 4, 5]
let sum = numbers.reduce((total, item) => total + item)

这里是利用了箭头函数可以省略return的特性。

这里的传入的函数接收了两个参数(实际上可以接收四个,但这里不需要后面两个),这两个参数通过英文应该就可以看懂。

reduce()方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

注意: reduce()对于空数组是不会执行回调函数的。

这里可以给一个初始值:

let numbers = [1, 2, 3, 4, 5]
let sum = numbers.reduce((total, item) => {
  return total + item
}, 10)

之前的和是15,这次加上了一个初始值,就是25了。

实践

假设我们有一个TXT文件。

徐航宇游泳4分钟
徐航宇跑步1分钟
徐航宇跳远3米
刘好游泳5分钟
刘好跑步2分钟
刘好跳远1米

我们用node去读取他,让它变成一个JSON对象,就像这样:

{
  "徐航宇": [
    {
      "项目": "游泳",
      "时间": "4分钟"
    },
    {
      "项目":"跑步",
      "时间":"1分钟"
    }
  ],
  "刘好": [
    // ...
  ]
}

上代码!

import fs from 'fs'

let output = fs.readFileSync('data.txt', 'utf-8')
.trim() // 去掉字符串头尾的空格,返回新数组
.split('\n') // 在换行处截断,组成数组
.map(line => line.split('\t')) // 每一行根据制表符断开,组成数组

这一步之后,我们应该得到什么?

[
  ["徐航宇", "游泳", "4分钟"],
["徐航宇", "跑步", "1分钟"],
["徐航宇", "跳远", "3米"],
["刘好", "游泳", "5分钟"],
["刘好", "跑步", "2分钟"],
["刘好", "跳远", "1米"]
]

接下来想要变成对象,该怎么做呢?

首先第一步,我们想一想,要想变成最终的JSON数据,我们需要对每一项进行处理:

  • 把每一个数组的第一个作为对象的属性名
  • 把每一个数组的二三项组成新的对象,放入该属姓名的值中

接下来就该reduce()出场了:

.reduce((customer, line) => {
  // 提取每个数组的第一项,作为传入对象的属姓名
  // 如果该项是以前没有的,那么将其初始化为空数组
  // 如果该项以前有,那么就不动他
    customer[line[0]] = customer[line[0]] === undefined ? [] : customer[line[0]]
customer[line[0]].push({
      name: line[1],
      time: line[2]
    })
    return customer
  }, {})

这样就成功了!

总结

总而言之,函数式编程如果归根结底,和直接写没有任何区别。但是它提供给了我们一种写更少的代码,完成更多的事情的方法。

人是难免会出错的,代码量越大、错误可能就会越多,所以更少代码的函数式编程,往往意味着:更少的bug。

(完)

(0)

相关推荐

  • js 高阶函数reduce ——数组取交集、并集

    两个数组取交集 vs 多个数组取交集 => js reduce函数的妙用 1.reduce函数的用法及取数组交集 <script> // 值集数组 let arr1 = [1,2] ...

  • 15个你应该掌握的JavaScript数组方法

    点击链接 15个你应该掌握的JavaScript数组方法 WEB前端开发社区 2021-10-12 什么是数组方法? 数组方法是 JavaScript 内置的函数,可以应用于数组.每种方法都有一个独特 ...

  • 拿 C# 搞函数式编程 - 3

    前言 今天和某个人聊天聊到了 C# 的 LINQ,发现我认识的 LINQ 似乎和大多数人认识的 LINQ 不太一样,怎么个不一样法呢?其实 LINQ 也可以用来搞函数式编程. 当然,并不是说写几个 l ...

  • 如何去使用Python里面的函数式编程和闭包?

    对于开发者来说除了基础语法之外,一些比较常用的开发手段也是需要去学习和使用的.这里小千就来教大家如何去使用Python里面的函数式编程和闭包. 函数式编程 函数式编程这个概念我们可能或多或少都听说过, ...

  • F# 函数式编程之 - 一个例子

    经过本系列前面几篇文章对 F# 的介绍,是时候来一个比较小巧的例子了. 这个例子的原文见 https://fsharpforfunandprofit.com/posts/roman-numerals/ ...

  • Python中的函数式编程教程,学会用一行代码搞定所有内容

    https://m.toutiao.com/is/JEUURVQ/ 前言 在本文中,您将了解什么是函数范型,以及如何在Python中使用函数式编程.在Python中,函数式编程中的map和filter ...

  • Stata的面向函数式编程——以独董职业背景多元化赫芬达尔指数的计算过程为例

    众所周知,在学习python的时候,老师们一般喜欢将编程的思维分成面向过程.面向函数和面向对象式编程几种,学习的过程层层递进.在使用stata的时候,我们一般都喜欢面向过程式编程,这也是stata经常 ...

  • Java函数式编程和lambda表达式

    为什么要使用函数式编程# 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基 ...

  • 浅谈函数式编程

    函数式编程(Functional Programming)是一种编程风格,它是相对于指令式编程风格而言的,常见的面向对象编程就是指令式编程风格. 指令式编程是面向计算机硬件的抽象,有变量(对应着存储单 ...

  • 函数式编程入门

    2020-03-10 17:23:49 1. 概述 1.1 函数式编程简介 Java作为面向对象的编程语言,如果按照编程种类划分属于命令式编程(Imperative Programming).常见的编 ...

  • 写 Python 代码不可不知的函数式编程技术

    2021-10-09 本文对 Python 中的函数式编程技术进行了简单的入门介绍. 近来,越来越多人使用函数式编程(functional programming).因此,很多传统的命令式语言(如 J ...