arg是什么函数_JavaScript 函数式编程 - 基本范式简介

函数式编是一种编程范式,一种编写计算机程序的风格。类似面向有对象有封装,继承,多态的概念,函数式编程也有自己的一些编程范式。下面简单介绍 JavaScript 的函数式编程范式,了解了下面的范式后,你可以说自己已经入门。

高阶函数 (Higher order function)

满足下面两个条件至少一个就算是高阶函数:

  • 接收一个函数作为参数 (Accept a function as a argument)
  • 返回一个函数 (Returns a function)
const withCount = fn => {
  let count = 0
  return (...args) => {
        count += 1
    console.log(`fn being called ${count} times`)
    return fn(...args)
  }
}

const add3 = x => x + 3
const countedAdd3 = withCount(add3)

countedAdd3(3) // fn being called 1 times
countedAdd3(3) // fn being called 2 times
countedAdd3(3) // fn being called 3 times

不可变数据 (Immutable data)

Mutable data 在创建后可以改变,Imutable data 在创建后不允许改变,函数式编程一般使用不可变数据,数据一旦创建后,不允许修改,只能替换。

// mutable example
let a = [1, 2, 3]
a.push(4)
console.log(a, 'a') // [ 1, 2, 3, 4 ] 'a'

// immutable example
let b = [1, 2, 3]
const immutablePush = (arr, arg) => [...arr, arg]
let c = immutablePush(b, 4)
console.log(c, 'c') // [ 1, 2, 3, 4 ] 'c'
console.log(b, 'b') // [ 1, 2, 3 ] 'b'

柯里化 (Currying)

柯里化指的是将多个参数的函数变成多个一个参数的函数的过程

// 两个参数的函数
const add = (x, y) => x + y
const r = add(1, 2)
console.log(r) // 3

// 多个一个参数的函数
const curryingAdd = x => y => x + y

const add2 = curryingAdd(2) // 可以复用

const rr = add2(1) // 3
const rr2 = add2(2) // 4

纯函数 (Pure Function)

纯函数类似数学范畴的函数定义

f(x) = x + 1

同时满足下面三个条件才叫做纯函数

  • output 只依赖 input
  • 同样的 input 会得到同样的 output
  • 并且不产生任何副作用
// 不是纯函数的例子
// 依赖外部变量
let num = 1
const addByCount = x => x + count

// 同样的输入,不同输出
const addByRandom = x => x + Math.random() * 10

// 产生 side effect
let count = 0
const addOne = x => {
  count += 1
  return x + 1
}

// 产生 side effect
const addOneWithConsole = x => {
  console.log(x)
  return x + 1
}

// 纯函数
const pureFunc = x => x + 1

管道/组合 (Pipe / Compose)

多个函数按顺序处理一个数据的时候写起来会很丑(包很多层),pipe / compose 可以将多个函数合成一个函数,从而简化逻辑,看起来更有秩序

const text = 'hello world'

// 三个函数按顺序操作一个变量
const toUpper = text => text.toUpperCase()
const addExclamation = text => `${text}!`
const double = text => `${text}${text}`
const r = double(addExclamation(toUpper(text)))
console.log(r, 'r')

// 同样操作,改用 pipe 函数的方式
const pipe = (...fns) => (arg) => fns.reduce((sum, fn) => fn(sum), arg)
const rr = pipe(toUpper, addExclamation, double)(text)
console.log(rr, 'rr')

函数式编程的 Debug 方式

如果都是纯函数,debug 也是很方便的一件事,我们可以在 funtion 流处理数据的中间加上"埋点",比如下面的log() 函数

const text = 'hello world'

const toUpper = text => text.toUpperCase()
const addExclamation = text => `${text}!`
const double = text => `${text}${text}`

// logger
const log = msg => x => {
  console.log(msg, x)
  return x
}

const pipe = (...fns) => (arg) => fns.reduce((sum, fn) => fn(sum), arg)
const rr = pipe(toUpper, log('1st'), addExclamation, log('2nd'), double)(text)
console.log(rr, 'rr')

函数式与面向对象对比

比如我们要做一个太阳系出来,函数式编程更像是定好初始状态和物理定律,剩下的就不用操心了,因为初始状态会根据物理定律来进行改变,知道前一秒的状态,后一秒也是完全可预测的。

面向对象更像是抽象出一个个类,比如我有恒星类,行星类,小行星类。然后定义恒星有什么状态,有什么方法,行星有什么状态,有什么方法。然后 new 一个恒星出来,new 几个行星出来,让他们调用自己或者别人的方法,来改变自身的状态。每个行星自己的状态都是不可预测的,比如你不知道下一秒别人会不会碰撞你(即你不知道别人的状态,而别人的状态会影响到你的状态)。

8b78cae4112c82bbb6935ffde0095c04.png

总而言之,面向对象编程更适合有良好解耦的多模块系统,每个模块维护自己的数据与方法,只对外暴露接口。函数式编程更适合需要从整体上对整个程序进行控制的系统。

Ref

  • https://egghead.io/courses/just-enough-functional-programming-in-javascript
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值