JavaScript 中的函数式模式与命令式模式 if / else if (no else) 对数组求和 for / if (1) for / if (2) 提前中断循环 if / else if / else 设置属性 修改数组 类 嵌套 for 循环 空值保护 结束

2025-06-09

JavaScript 中的函数式模式与命令式模式

如果/否则

如果(没有其他情况)

对数组求和

对于/如果 (1)

对于/如果 (2)

尽早打破循环

如果/否则 如果/否则

设置属性

修改数组

课程

嵌套 for 循环

空守卫

结尾

这篇文章的目的并非论证某种范式优于另一种,而只是展示一些常见的模式及其功能对等物。

如果我遗漏了什么模式,而你想看看,请在下方评论区留言。注意,请将你的模式精简到最小公分母。我可没法转换一个 100 行的函数!;)

如果/否则

至关重要的

const hour = 14
let greeting

if (hour < 18) {
  greeting = 'Good day';
} else {
  greeting = 'Good evening';
}
Enter fullscreen mode Exit fullscreen mode

功能

现在可以if作为函数重新使用getGreeting

一个:

const isDay = hour => hour < 18
const getGreeting = hour => isDay(hour) ? 'Good Day' : 'Good Evening'
const greeting = getGreeting (hour)
Enter fullscreen mode Exit fullscreen mode

乙:

import ifElse from 'mojiscript/logic/ifElse'

const isDay = hour => hour < 18
const getGreeting = ifElse (isDay) (() => 'Good Day') (() => 'Good evening')
const greeting = getGreeting (hour)
Enter fullscreen mode Exit fullscreen mode

如果(没有其他情况)

至关重要的

let name = 'joel'

if (name != null) {
  name = name.toUpperCase()
}
Enter fullscreen mode Exit fullscreen mode

功能

isNotnull并且toUpperCase是可重复使用的函数。name不会被覆盖,而是upperName会被创建。

import when from 'mojiscript/logic/when'

const isNotNull = obj => obj != null
const toUpperCase = when (isNotNull) (string => string.toUpperCase ())

const name = 'joel'
const upperName = toUpperCase (name)
Enter fullscreen mode Exit fullscreen mode

对数组求和

至关重要的

const values = [1, 2, 3]

let sum = 0
for (const x of values) {
  sum = sum + x
}
Enter fullscreen mode Exit fullscreen mode

功能

不要变异sum

一个:

const values = [1, 2, 3]

const add = (x, y) => x + y
const sum = values.reduce(add)
Enter fullscreen mode Exit fullscreen mode

乙:

import reduce from 'mojiscript/list/reduce'

const add = x => y => x + y
const sum = reduce (add) (0)

const values = [1, 2, 3]
sum (values)
Enter fullscreen mode Exit fullscreen mode

对于/如果 (1)

至关重要的

const values = [1, 2, 3, 4, 5]

let evens = []
for (const x of values) {
  if (x % 2 === 0) {
    evens.push(x)
  }
}
Enter fullscreen mode Exit fullscreen mode

功能

不要变异evens

import filter from 'mojiscript/list/filter'

const values = [1, 2, 3, 4, 5]

const isEven = num => num % 2 === 0
const evens = filter (isEven) (values)
Enter fullscreen mode Exit fullscreen mode

对于/如果 (2)

至关重要的

const values = [1, 2, 3, 4, 5]

for (const x of values) {
  if (x % 2 === 0) {
    console.log(`${x} isEven`)
  }
}
Enter fullscreen mode Exit fullscreen mode

功能

用于when条件执行。

import map from 'mojiscript/list/map'
import when from 'mojiscript/logic/when'

const isEven = num => num % 2 === 0
const logWhenEven = when (isEven) (x => console.log (`${x} isEven`))

const values = [1, 2, 3, 4, 5]
map (logWhenEven) (values)
Enter fullscreen mode Exit fullscreen mode

尽早打破循环

至关重要的

const values = [1, 2, 3]
let sum = 0
for (const x of values) {
  if (x > 3) break
  sum = sum + x 
}
Enter fullscreen mode Exit fullscreen mode

功能

reduceWhile类似于reduce,但接受谓词以提前“中断”。

import reduceWhile from 'mojiscript/list/reduceWhile'

const add = x => y => x + y
const lte3 = num => num <= 3

const sum = reduceWhile (() => lte3) (add) (0) (values)
Enter fullscreen mode Exit fullscreen mode

如果/否则 如果/否则

至关重要的

const fn = temp => {
   if (temp === 0) return 'water freezes at 0°C'
   else if (temp === 100) return 'water boils at 100°C'
   else return `nothing special happens at ${temp}°C`
}

fn(0) //=> 'water freezes at 0°C'
fn(50) //=> 'nothing special happens at 50°C'
fn(100) //=> 'water boils at 100°C'
Enter fullscreen mode Exit fullscreen mode

功能

import cond from 'mojiscript/logic/cond'
import $ from 'mojiscript/string/template'

const fn = cond([
  [0, 'water freezes at 0°C'],
  [100, 'water boils at 100°C'],
  [() => true, $`nothing special happens at ${0}°C`]
])

fn(0) //=> 'water freezes at 0°C'
fn(50) //=> 'nothing special happens at 50°C'
fn(100) //=> 'water boils at 100°C'
Enter fullscreen mode Exit fullscreen mode

设置属性

至关重要的

const obj = {
  one: 1
}

obj.two = 2
Enter fullscreen mode Exit fullscreen mode

功能

不要改变原始对象,浅克隆它,然后添加新的道具。

注意:当对象可变时,必须进行深度克隆。如果对象不可变,则可以进行浅克隆,这具有明显的性能优势。

const obj = {
  one: 1
}

const newObj = {
  ...obj,
  two: 2
}
Enter fullscreen mode Exit fullscreen mode

修改数组

至关重要的

const values = [1, 2, 3]
values.push(4)
Enter fullscreen mode Exit fullscreen mode

功能

不要变异values

一个:

const values = [1, 2, 3]
const newValues = [...values, 4]
Enter fullscreen mode Exit fullscreen mode

乙:

对于大型数组,使用像列表这样的不可变库来获得高性能的不可变数组。

import L from 'list'

const values = L.from([1, 2, 3])
const newValues = L.append(4, values)
Enter fullscreen mode Exit fullscreen mode

课程

至关重要的

容易出错。

class Cat {
  constructor() {
    this.sound = 'Meow'
  }

  talk() {
    return this.sound
  }
}

const cat = new Cat()
const talk = cat.talk

cat.talk() //=> 'Meow'
talk() //=> Error: Cannot read property 'sound' of undefined
Enter fullscreen mode Exit fullscreen mode

功能

将功能与数据分离以实现最大程度的可重用性。

const cat = {
  sound: 'Meow'
}

const dog = {
  sound: 'Woof'
}

const talk = animal => animal.sound

talk (cat) //=> 'Meow'
talk (dog) //=> 'Woof'
Enter fullscreen mode Exit fullscreen mode

嵌套 for 循环

至关重要的

let box = ''
for (let y = 0; y < 5; y++) {
  for (let x = 0; x < 5; x++) {
    box = box + '* '
  }
  box = box + '\n'
}
Enter fullscreen mode Exit fullscreen mode

功能

不再嵌套。不可变。

import reduce from 'mojiscript/list/reduce'
import range from 'mojiscript/list/range'

const makeCols = cols =>
  reduce (acc => () => acc + '* ') ('') (range (0) (cols))

const makeBox = ({ cols, rows }) =>
  reduce (acc => () => `${acc}${makeCols (cols)}\n`) ('') (range (0) (rows))

const box = makeBox ({ cols: 5, rows: 5 })
//=> ​​​​​* * * * * ​​​​​
//=> ​​​​​* * * * * ​​​​​
//=> ​​​​​* * * * * ​​​​​
//=> ​​​​​* * * * * ​​​​​
//=> ​​​​​* * * * * ​​​​​
Enter fullscreen mode Exit fullscreen mode

并且可重复使用!

const makeTriangle = length =>
  reduce
    (acc => i => `${acc}${' '.repeat(length - i)}${makeCols (i + 1)}\n`)
    ('')
    (range (0) (length))

const triangle = makeTriangle (5)
//=>​​​​​     * ​​​​​
//=>​​​​​    * * ​​​​​
//=>​​​​​   * * * ​​​​​
//=>​​​​​  * * * * ​​​​​
//=>​​​​​ * * * * * ​​​​​
Enter fullscreen mode Exit fullscreen mode

空守卫

至关重要的

const toUpper = string => {
  if (string != null) {
    return string.toUpperCase()
  }
}
Enter fullscreen mode Exit fullscreen mode

功能

一个:

此示例将参数包装在一个Maybe类型中,然后在最后将其解包。在典型的函数式编程应用中,您会Maybe在整个应用中使用 ,因此无需对 进行包装和解包string。因此,这比您通常看到的要冗长一些。

import S from 'sanctuary'

const toUpper = S.pipe ([
  S.toMaybe,
  S.map (string => string.toUpperCase ()),
  S.maybeToNullable
])

// If you use `Maybe` throughout your app, this would be your `toUpper` function.
const toUpper = S.map (string => string.toUpperCase ())
Enter fullscreen mode Exit fullscreen mode

乙:

maybe是一个函数装饰器,仅在传入参数时执行函数。现在我们的空值保护可以复用了。更多关于函数装饰器的信息,请访问:函数式 JavaScript:函数装饰器(第二部分)#JavaScript

const maybe = func => (...args) =>
  args.length === 0 || args[0] == null
    ? args[0]
    : func(...args)

const toUpper = maybe(string => string.toUpperCase ())
Enter fullscreen mode Exit fullscreen mode

结尾

我的文章非常注重函数式 JavaScript,如果您需要更多 FP,请在这里关注我,或在 Twitter 上关注我@joelnet

更多文章
问我一些关于函数式编程的愚蠢问题
让我们一起制作一个 DEV.to CLI...
让我们讨论一下 JavaScript 的自动生成文档工具

干杯!

鏂囩珷鏉ユ簮锛�https://dev.to/joelnet/function-vs-imperative-patterns-in-javascript-505h
PREV
如何使用 Cloudflare 和 S3 End 设置我自己的个人 CDN
NEXT
函数式编程:IF 的替代方案 #Functional #JavaScript #Functors 解决方案 A:ifVal 辅助函数 解决方案 B:Functors 结束示例一 示例二 示例三