处理 DOM 操作时的纯函数

Ola*_*sen 10 javascript dom functional-programming canvas

我试图围绕纯函数进行思考,但我不确定我是否真的理解它。我知道纯函数不应该改变外部状态,并且只要它具有相同的输入,它每次都应该返回相同的输出。

我知道例如这个函数是不纯的,因为它改变了程序其他部分可能使用的 car 变量:

const addToCart = (cart, item) => { 
  cart.push(item); 
  return cart; 
};
Run Code Online (Sandbox Code Playgroud)

纯状态下的相同函数:

const addToCart = (cart, item) => { 
  const newCart = lodash.cloneDeep(cart); 
  newCart.push(item); 
  return newCart; 
};
Run Code Online (Sandbox Code Playgroud)

这对我来说很有意义。我了解到纯函数应该总是返回一些东西。

但是,我正在处理一些需要我使用 HTML5 画布元素的东西,我有这个功能可以清除画布:

function clearCanvas(canvas) { 
  canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); 
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能使上述函数纯?我意识到它是不纯的,因为它不返回任何东西,而且它改变了画布变量的状态。DOM 操作本质上是不纯的吗?

任何帮助,将不胜感激 :)

the*_*sti 5

DOM 操作是不纯粹的。您无法以“纯粹”的方式清除画布。

任何改变系统状态或与外界交互的事物都被认为具有副作用,并且在纯函数式编程环境中应该避免副作用。

然而,DOM 操作显然可以实现这两点;清除画布既是状态的更改(未清除到已清除),而且用户可以看到此更改。


您可能想更深入地了解函数式编程,这似乎是您试图通过纯/不纯函数方法实现的目标。

函数式编程的目标是避免更改状态,例如,一个程序不会更改对象,而另一个程序正在使用该对象,这可能会产生意外和不需要的结果。


Tha*_*you 5

IO 单子

你可能对 IO monad 感兴趣——本质上 IO 包含一个thunk或一个惰性函数,它只在我们调用runIO. 更重要的是,我们可以在 IO 和map一个允许我们对包含的值进行操作的普通函数中保持封闭。

如需阅读和另一个 IO 实现,请参阅Brian Lonsdorf 书中的第 9 章:Monadic Onions


小演示

// IO :: (void -> a) -> IO a
const IO = f => ({
  // runIO :: void -> a
  runIO: f,
  // map :: IO a => (a -> b) -> IO b
  map: g =>
    IO(() => g(f())),
  // chain :: IO a => (a -> IO b) -> IO b
  chain: g =>
    IO(g(f()).runIO)
})

// IO.of :: a -> IO a
IO.of = x => IO(() => x)

// log :: String -> a -> IO a
const log = label => x =>
  IO(() => (console.log(label, x), x))

// $ :: String -> IO HTMLElement
const $ = x =>
  IO(() => document.querySelector(x))

// getText :: HTMLElement -> String
const getText = e =>
  e.textContent

// main :: String -> IO String
const main = selector =>
  $(selector)
    .map(getText)
    .chain(log('A'))
    .map(s => s.toUpperCase())
    .chain(log('B'))
    .runIO()

main('title')
// A hello world
// B HELLO WORLD
Run Code Online (Sandbox Code Playgroud)
<title>hello world</title>
Run Code Online (Sandbox Code Playgroud)