In simple terms, what's the difference between a thunk and a Higher Order Function?

I understand that both are functions that return functions

Your understanding is slightly incorrect

  • Thunks can return a value of any type – not just a Function type
  • Higher-order functions can return a value of any type – not just a Function type

My experience so far with thunks have been using them to return functions as opposed to just action objects so that I can work with async requests in Redux.

Thunks (and higher-order functions, for that matter) are not intrinsically related to any particular library (React, Redux) or any particular control flow (sync, async). A thunk is just a nullary function – they have a variety of common uses cases, but most commonly are used to delay the evaluation of a specific computation.

A closure is an implementation of a High Order Function (HOF) in order to create a new scope for private variables...right? Other examples of HOFs include map, reduce and filter.

A closure is not necessarily an implementation of a higher-order function. The function keyword (and => arrow function syntax) does create a closure tho which does have a new (lexical) scope, yes.

Is there any thing else that explicitly defines a difference between the two?

Yes. How they are the same:

  • they are both functions
  • they can both return values of any type

How they are different:

  • thunks are nullary functions (they accept no arguments)
  • higher-order functions accept a function as an argument and/or return a function

Perhaps the most critical distinction:

  • A thunk can only be considered a higher-order function if it returns a function.

Thunks are functions wrap expressions in order to delay their evaluation.

This delay is achieved in Redux thunk a when an action is called it returns a function. This function that is returned can then be called at a later time.

Here is an example of a thunk action.

function incrementAsync() {
  // the below function is called by Redux Thunk middleware below.
  return dispatch => {
    setTimeout(() => {
      // Yay! Can invoke sync or async actions with `dispatch`
      dispatch(increment());
    }, 1000);
  };

A higher order function is just a function that either returns a function or takes a function as one of its arguments. Because this function returns another function that takes dispatch as an argument this is an example of a higher order function.

The code from the redux thunk middleware resembles this

function createThunkMiddleware() {
  return store => next => action => {
    if (typeof action === 'function') {

      // since action is a function it is a thunk action creator
      // so call it with store methods
      return action(store.dispatch, store.getState);

    }
    // action is not a function so redux thunk ignores it
    return next(action);
  };
}

As soon as our thunk action creator is called it sends the action function through the middleware chain. When it reaches our thunk middleware this action is recognised as a function and therefore called again with the dispatch and getState methods of the store.

Because of this second function call we are now in the scope of the returned function from our thunk action creator. This means that we can now execute asynchronous logic and still have access to the store's getState and dispatch methods. This is why our thunk action creator can be considered a thunk expression. By using a higher order function we can have access to, yet postpone the use of the store's dispatch or getState method to a future time. As seen below, the increment action is called after a one second delay.

function incrementAsync() {
  // the below function is called by Redux Thunk middleware below.
  return dispatch => {
    setTimeout(() => {
      // Yay! Can invoke sync or async actions with `dispatch`
      dispatch(increment());
    }, 1000);
  };