Search code examples
javascriptfunctionreduxclosuresreselect

What function returning another function with parameters declared also as constants exactly do?


I'm completely lost. Below is a short code from an article considering Reselect library:

const shopItemsSelector = state => state.shop.items
const taxPercentSelector = state => state.shop.taxPercent

const subtotalSelector = state => {
  const items = shopItems(state)
  return items => items.reduce((acc, item) => acc + item.value, 0)
}

const taxSelector = state => {
  const subtotal = subtotalSelector(state)
  const taxPercent = taxPercentSelector(state)
  return (subtotal, taxPercent) => subtotal * (taxPercent / 100)
}

export const totalSelector = state => {
  const subtotal = subtotalSelector(state)
  const tax = taxSelector(state)
  return (subtotal, tax) => ({ total: subtotal + tax })
}

Can someone explain what function totalSelector returns?

I see it returns another function with parameters subtotal and tax, but why there are constants with the same names declared and how they correspond to the parameters of returned function?


Solution

  • Can someone explain what function totalSelector returns?

    Almost certainly not what the author meant it to return. :-)

    What it returns is a function that, when called with two arguments, returns an object with a total property that's the sum of the two arguments passed in. Everything in totalSelector before the return line is completely pointless and ignored, because the author has shadowed the subtotal and tax constants with parameters in the arrow function it's returning:

    export const totalSelector = state => {
      const subtotal = subtotalSelector(state) // <=== These
      const tax = taxSelector(state)           // <=== constants
      //      vvvvvvvvvvvvv------------ are shadowed by these parameter declarations
      return (subtotal, tax) => ({ total: subtotal + tax })
      //                                  ^^^^^^^^^^^^^^ -- so this uses the parameters
    }
    

    So the subtotal and tax in the arrow function's body are the parameters, not the constants.

    The author probably meant to do this:

    export const totalSelector = state => {
      const subtotal = subtotalSelector(state)
      const tax = taxSelector(state)
      return () => ({ total: subtotal() + tax() })
      //     ^^                      ^^      ^^
    }
    

    ...though it's hard to be sure. That accepts a state object and returns a function that, when called, will select the subtotal and tax as of that call and return a total. Note that it accepts no parameters, and calls the functions it created via subtotalSelector(state) and taxSelector(state).

    subtotalSelector and taxSelector have the same problem.