函数式编程:IF 的替代方案 #Functional #JavaScript #Functors 解决方案 A:ifVal 辅助函数 解决方案 B:Functors 结束示例一 示例二 示例三

2025-06-09

函数式编程:IF 的替代方案 #Functional #JavaScript #Functors

解决方案 A:ifVal 辅助函数

解决方案 B:函子

结尾

示例一

示例二

例三

有几次我被问到“在函数式编程中你将如何做 X?”我非常喜欢这些类型的问题。

我会尽力回答每一个问题,但我认为有很多问题足够有趣,值得单独写一篇文章。

因此,在本文中,我想演示如何以更实用的方式重新创建这个命令功能。

此函数有一个if没有 的语句else。因此,虽然ternary运算符可以工作,但并不理想。

// A basic redux-thunk action that only dispatches when value exists
const someAction = value => dispatch => {
  const item = getItem(value)
  if (item != null) {
    dispatch({ type: 'ACTION', item })
  }
}
Enter fullscreen mode Exit fullscreen mode

这里我们只需要dispatch在有的时候运行value,否则我们什么也不做。

一种选择是使用短路运算符:

// short circuit
const someAction = value => dispatch => {
  const item = getItem(value)
  item && dispatch({ type: 'ACTION', item })
}

// ternary
const someAction = value => dispatch => {
  const item = getItem(value)
  item ? dispatch({ type: 'ACTION', item }) : null
}
Enter fullscreen mode Exit fullscreen mode

短路和三元以及两种方法都可以解决这个问题,但让我们再看几个。

解决方案 A:ifVal 辅助函数

为了更实用地实现这一点,我将创建一个辅助函数。我会先用老套的方式编写这个辅助函数,然后再逐步分解,以便每个人都能轻松理解。

// 1: old school
function ifVal (x, f) {
  if (x == null) {
    return null
  } else {
    return f(x)
  }
}

// 2: convert to arrow function
const ifVal = (x, f) => {
  if (x == null) {
    return null
  } else {
    return f(x)
  }
}

// 3: convert if/else to a ternary operator
const ifVal = (x, f) => {
  return x == null ? null : f(x)
}

// 4: voilà!
const ifVal = (x, f) => x == null ? null : f(x)
Enter fullscreen mode Exit fullscreen mode

现在我们可以修改我们的someAction函数来ifVal代替经典的if块。

// functional alternative
const someAction = value => dispatch =>
  ifVal(getItem(value), item => dispatch({ type: 'ACTION', item }))
Enter fullscreen mode Exit fullscreen mode

以下是快速简便的 Twitter 截图的比较:

/**
 * execute the function if the value is not null or undefined
 * @param {Object} val - the value to test
 * @param {Function} fn - the function to execute.
 * @returns {Object} - null or the value of the executed function.
 */
const ifVal = (val, fn) => val == null ? null : fn(val)

// imperative example
const someAction = value => dispatch => {
  const item = getItem(value)
  if (item!= null) {
    dispatch({ type: 'ACTION', item })
  }
}

// functional example
const someAction = value => dispatch =>
  ifVal(getItem(value), item => dispatch({ type: 'ACTION', item }))
Enter fullscreen mode Exit fullscreen mode

进一步阅读

查看 Ramda 的whenunlessifelse以了解其他有用且类似的功能。

解决方案 B:函子

我们也可以使用Maybe 类型。Maybe 类型要么包含Just一个值,要么Nothing包含一个确切值的类型。

对于这个例子,我将使用Sanctuary库中的 Maybe Type

它看起来有点像这样:

/* Examples of Sanctuary's Maybe */

toMaybe(null) //=> Nothing
toMaybe(undefined) //=> Nothing
toMaybe(0) //=> Just(0)
toMaybe(false) //=> Just(false)
toMaybe(123) //=> Just(123)
toMaybe({ name: 'joel' }) //=> Just({ name: 'joel' })
Enter fullscreen mode Exit fullscreen mode

Maybe 类型非常简单,我之所以想使用它是因为它可以很好地协同map工作Maybe,所以它被赋予了一个特殊的名字,即Functor

有些库(例如ramda-fantasy)的语法比较流畅,但本文使用的是 Sanctuary。不过,了解这两个库是等价的还是不错的。

const double = x => x * 2

// ramda-fantasy
Maybe.toMaybe(333).map(double) //=> Just(666)

// Sanctuary
map(double, toMaybe(333)) //=> Just(666)
Enter fullscreen mode Exit fullscreen mode

例子:

const double = x => x * 2

// map is ignored
map(double, toMaybe(null)) //=> Nothing

// no more null exceptions!
map(val => val.something(), toMaybe(null)) //=> Nothing

// map is mapped
map(double, toMaybe(333)) //=> Just(666)
Enter fullscreen mode Exit fullscreen mode

所有doSomething与 Maybe 一起看起来会像这样:

import { toMaybe, map } from 'sanctuary'

const someAction = value => dispatch => {
  const item = getItem(value)
  const maybeValue = toMaybe(item)
  map(item => dispatch({ type: 'ACTION', item }))(maybeValue)
}
Enter fullscreen mode Exit fullscreen mode

这里我们有三个函数,getItemtoMaybemap,它们可以组合成一个新的函数。我们可以将值传递给这个新函数,它会首先流入getItem,然后toMaybe最终流入我们的map

const someAction = value => dispatch => pipe([
  getItem,
  toMaybe,
  map(value => dispatch({ type: 'ACTION', value })),
], value)
Enter fullscreen mode Exit fullscreen mode

最后再发一条完美的推文:

import { toMaybe, map, pipe } from 'sanctuary'

// imperative example
const someAction = value => dispatch => {
  const item = getItem(value)
  if (item != null) {
    dispatch({ type: 'ACTION', item })
  }
}

// maybe functor example
const someAction = value => dispatch => pipe([
  getItem,
  toMaybe,
  map(value => dispatch({ type: 'ACTION', value })),
], value)

someAction(666)(dispatch) // Action is dispatched!
someAction(null)(dispatch) // Nothing happens
Enter fullscreen mode Exit fullscreen mode

结尾

希望你喜欢这段小小的函数式学习之旅。如果你喜欢,或者遇到问题,或者想看更多类似的文章,请在评论区告诉我。如果你真的想激励我,请在这里或Twitter关注我;如果你喜欢这篇文章,也请分享出去!

干杯!

鏂囩珷鏉ユ簮锛�https://dev.to/joelnet/function-programming-how-would-you-if-no-else-javascript-59ai
PREV
JavaScript 中的函数式模式与命令式模式 if / else if (no else) 对数组求和 for / if (1) for / if (2) 提前中断循环 if / else if / else 设置属性 修改数组 类 嵌套 for 循环 空值保护 结束
NEXT
解构 Map、Filter 和 Reduce 累加器 Reduce Map Filter 其他特性 额外加分 PS 总结