前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实战:从 Redux 中的代码片段中应用柯里化!

实战:从 Redux 中的代码片段中应用柯里化!

作者头像
掘金安东尼
发布2022-09-19 11:12:13
9780
发布2022-09-19 11:12:13
举报
文章被收录于专栏:掘金安东尼

theme: smartblue

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

本文通译自:JavaScript Currying: A Practical Example


柯里化(Currying):是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数、返回最终结果的新函数的技术。

想必大家已经不算陌生!

例🌰:

代码语言:javascript
复制
const add = (a,b,c) => {
   return a+b+c
}
add(1,2,3) // 6
代码语言:javascript
复制
const addCurry = a => b => c => a+b+c
addCurry(1)(2)(3) // 6

addCurry 的 return 版本写法:

代码语言:javascript
复制
const addCurryReturn = (a) => { 
  return (b)=> { 
    return (c)=> { 
      return a+b+c 
    } 
  } 
}

OK,有了基本的认知后,直接上实战:柯里化 && Redux

以下代码从 Redux 中摘录:

代码语言:javascript
复制
// Partial file
...
extraReducers: {
  [signup.pending.toString()]: (state, action) => {
    state.loading = true
    state.error = false
    state.fulfilled = false
  },
  [signup.fulfilled.toString()]: (state, action) => {
    state.loading = false
    state.error = false
    state.fulfilled = true
  },
  [signup.rejected.toString()]: (state, action) => {
    state.loading = false
    state.error = true
    state.fulfilled = false
  },
  [signin.pending.toString()]: (state, action) => {
    state.loading = true
    state.error = false
    state.fulfilled = false
  },
  [signin.fulfilled.toString()]: (state, action) => {
    state.loading = false
    state.error = false
    state.fulfilled = true
  },
  [signin.rejected.toString()]: (state, action) => {
    state.loading = false
    state.error = true
    state.fulfilled = false
  },
}
...

从感官上看,这样的写法 —— 太重复冗余!

代码语言:javascript
复制
    state.loading = true
    state.error = false
    state.fulfilled = false

对于 state 的设置必须抽象;

我们可以创建一个函数,将 fulfilledloadingerror 设为可配置项,默认值为 false

代码语言:javascript
复制
const setStatus = (state, action) => ({fulfilled = false,loading = false,error = false}) => {
  state.fulfilled = fulfilled
  state.loading = loading
  state.error = error}
  
setStatus(state)({fulfilled:true}) 

然后,代码就优化成了这样:

代码语言:javascript
复制
extraReducers: {
  [signup.fulfilled.toString()]: (state, action) =>
    setStatus(state)({ fulfilled: true }),
  [signup.pending.toString()]: (state, action) =>
    setStatus(state)({ loading: true }),
  [signup.rejected.toString()]: (state, action) =>
    setStatus(state)({ error: true }),
  [signin.fulfilled.toString()]: (state, action) =>
    setStatus(state)({ fulfilled: true }),
  [signin.pending.toString()]: (state, action) =>
    setStatus(state)({ loading: true }),
  [signin.rejected.toString()]: (state, action) =>
    setStatus(state)({ error: true }),
}

没有设置为 true 的项,都默认为 fasle

还没完,(state, action) =>setStatus(state) 这一部分仍是重复冗余的,必须接着抽象;

我们将 setStatus 这样的写法:

代码语言:javascript
复制
const setStatus = (state) => ({fulfilled = false,loading = false,error = false}) =>  {
  state.fulfilled = fulfilled
  state.loading = loading
  state.error = error}

// 调用
setStatus(state)({fulfilled:true})

改造成以下写法:(敲重点, 柯里化就在此处体现✨)

代码语言:javascript
复制
// 更改传参顺序
const setStatus = ({fulfilled = false,loading = false,error = false}) => (state) => {
  state.fulfilled = fulfilled
  state.loading = loading
  state.error = error}

// 调用
setStatus({fulfilled:true})(state)

最终的改造结果

1. 改造前

代码语言:javascript
复制
extraReducers: {
  [signup.pending.toString()]: (state, action) => {
    state.loading = true
    state.error = false
    state.fulfilled = false
  },
  [signup.fulfilled.toString()]: (state, action) => {
    state.loading = false
    state.error = false
    state.fulfilled = true
  },
  [signup.rejected.toString()]: (state, action) => {
    state.loading = false
    state.error = true
    state.fulfilled = false
  },
  [signin.pending.toString()]: (state, action) => {
    state.loading = true
    state.error = false
    state.fulfilled = false
  },
  [signin.fulfilled.toString()]: (state, action) => {
    state.loading = false
    state.error = false
    state.fulfilled = true
  },
  [signin.rejected.toString()]: (state, action) => {
    state.loading = false
    state.error = true
    state.fulfilled = false
  },
}

2. 改造后

代码语言:javascript
复制
const setStatus = ({
    fulfilled = false,
    loading = false,
    error = false,
  }) =>
  (state, action) => {
    state.fulfilled = fulfilled
    state.loading = loading
    state.error = error
  }

extraReducers: {    
  [signup.pending.toString()]: setStatus({ loading: true }),
  [signup.fulfilled.toString()]: setStatus({ fulfilled: true }),
  [signup.rejected.toString()]: setStatus({ error: true }),

  [signin.pending.toString()]: setStatus({ loading: true }),
  [signin.fulfilled.toString()]: setStatus({ fulfilled: true }),
  [signin.rejected.toString()]: setStatus({ error: true }),
}

Why?

为什么改变了一个传参顺序,就能做到这样的简化效果?

噢,原来最根本的原因是以下的两种写法是等价的!(大道至简

代码语言:javascript
复制
// 写法 1
onClick((state)=> updateState(state))

// 写法 2
onClick(updateState)

其实,函数作为一等公民的思想 —— 即把函数当成一个值来进行传递,太开放(相对于OOP)!

比如:

代码语言:javascript
复制
const add = (a,b) => a+b
const sub = (a,b) => a-b
const calc = (a, b, cb) => cb(a,b)
calc(3,4, add) // 7
calc(3,4, sub) // -1

calc 是高阶函数(接受一个或多个函数作为输入)!

代码语言:javascript
复制
function getName(name) {
  return function greet(){
    console.log('Hello, ', name)
  }
}
const greet = getName('Karthick')
greet() // Hello,  Karthick

getName 也是高阶函数(输出一个函数),返回的是后续再调用的一个函数;

我敲!上面这段代码怎么有点眼熟,有点像我们之前在(《你觉得“惰性求值”在 JS 中会怎么实现?》)讲的 【惰性求值】 ?!

代码语言:javascript
复制
function * st1(){
    setTimeout(()=>{
        console.log("惰性求值")
    },1000)
    yield("后续再调用")
}

let aThunk=st1()
console.log(aThunk) // st1 {<suspended>}
aThunk.next() // {value: '后续再调用', done: false}

确实,闭包结构赋值的时候也不会计算,等到后续调用的时候才计算,就是惰性的呀~

新理解: 在 JavaScript 中,除了 Generator 可以实现惰性求值,闭包也可以呀!Thunk 就是一个闭包!

不是说柯里化吗?咋说到闭包了?

再看一例🌰:

代码语言:javascript
复制
const addCurryReturn = (a) => { 
  return (b)=> { 
    return (c)=> { 
      return a+b+c 
    } 
  } 
}
const add5 = addCurryReturn(5)
console.log(add5) // (b)=> { return (c)=> { return a+b+c } }

const add12 = add5(7)
console.log(add12) // (c)=> { return a+b+c }

add12(7) // 19

当我们调用 add12(7) 的时候,为什么会知道 x = 5y = 7,是因为闭包记住了先前执行中传递的值,这就是二者的关联。


以上,后面再遇见类似的代码结构知道怎么优化了吧!

撰文不易,点赞鼓励 👍👍👍👍👍👍 我是掘金安东尼,公众号同名,输出暴露输入,技术洞见生活,再会~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • theme: smartblue
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档