Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

JavaScript Currying: A Practical Example


Currying: a technique that converts a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function), and returns a new function that takes the remaining arguments and returns the ultimate result.

Presumably you are not strange!

Ex 🌰 :

Const add = (a, b, c) = > {return a + b + c} the add (1, 2, 3) / / 6Copy the code
const addCurry = a => b => c => a+b+c
addCurry(1)(2)(3) // 6
Copy the code

AddCurry return

const addCurryReturn = (a) => { 
  return (b)=> { 
    return (c)=> { 
      return a+b+c 
    } 
  } 
}
Copy the code

OK, after having the basic cognition, go to actual combat directly: Corrification && Redux

The following code is extracted from Redux:

// 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
  },
}
...
Copy the code

From the point of view of the senses, this way of writing — too repetitive!

    state.loading = true
    state.error = false
    state.fulfilled = false
Copy the code

The setting of state must be abstract;

We can create a function that sets depressing, Loading, and Error as configurable items. The default is false.

const setStatus = (state, action) => ({fulfilled = false,loading = false,error = false}) => {
  state.fulfilled = fulfilled
  state.loading = loading
  state.error = error}
  
setStatus(state)({fulfilled:true}) 
Copy the code

The code is then optimized to look like this:

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 }),
}
Copy the code

Items that are not set to true default to fasle;

That’s not all, (state, action) =>setStatus(state) is still redundant and must be abstracted;

We’ll write setStatus like this:

const setStatus = (state) => ({fulfilled = false,loading = false,error = false}) => { state.fulfilled = fulfilled Loading = loading state.error = error} // Call setStatus(state)({depressing :true})Copy the code

Change into the following writing :(knock key, currie is reflected here ✨)

// This is a big pity. // This is a big pity. Const setStatus = ({progressively = false,loading = false,error = false}) => (state) => {state Loading = loading state.error = error} // Call setStatus({depressing :true})(state)Copy the code

Final transformation results:

1. Before modification

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
  },
}
Copy the code

2. After transforming

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 }),
}
Copy the code

According to?

How can changing the order of a single parameter get such a simplified effect?

Oh, it turns out that the basic reason is that the following two ways are equivalent! (Avenue to Simplicity)

OnClick ((state)=> updateState(state))Copy the code

In fact, the idea of functions as first-class citizens — that is, passing functions as a value — is too open (as opposed to OOP)!

Such as:

Const add = (a,b) => a+b const sub = (a,b) => cb(a,b) => cb(a,b) calc(3,4, add) // 7 calc(3,4, 1) sub) // -1Copy the code

Calc is a higher-order function (that takes one or more functions as input)!

function getName(name) {
  return function greet(){
    console.log('Hello, ', name)
  }
}
const greet = getName('Karthick')
greet() // Hello,  Karthick
Copy the code

GetName is also a higher-order function (it outputs a function) and returns a function to be called later;

I knock! This code looks a bit familiar, a bit like the one we wrote in “How do you think lazy evaluation is implemented in JS?” Lazy evaluation? !

Function * st1(){setTimeout(()=>{console.log(" lazy evaluation ")},1000) yield} let aThunk=st1() console.log(aThunk) // St1 {<suspended>} athunk.next () // {value: 'next call ', done: false}Copy the code

Indeed, closures are not evaluated when they are assigned, but only when they are invoked later

In JavaScript, in addition to generators, lazy evaluation can be done with closures. Thunk is a closure!

What happened to corrification? What about closures?

Another example 🌰 :

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
Copy the code

The reason we know x = 5 and y = 7 when we call add12(7) is because the closure remembers the values passed in the previous execution, and that’s the connection.


Above, after meeting similar code structure to know how to optimize it!

👍👍👍👍 college

I am Anthony Nuggets, the public account of the same name, output exposure input, technical insights into life, goodbye ~