Q: How to understand what is happening with this higher order function closure I know my code below is wrong but there is clearly some bit of information I am missing. I have to write much more complex higher order functions but if I do not truly understand simple ones I have no chance.
hof.add should return the total of the two arguments passed. Very simple... 
But given I am to create this higher order function is must use closure.

    hof.add = function(add) {
      function makeAdd(a, b) {
        return add(a + b);
      }
      return makeAdd;
    };


it('returns total of the two arguments', () => {
        expect(hof.add(56, 5)).to.be.equal(56 + 5);
        expect(hof.add(91, -71)).to.be.equal(91 + -71);
      });

(framework given to build on top of)
hof.add = function() { };


A: Why do you create a function inside the returned function instead of just creating the right function initially? I would go something like this:
hof.add = function(a, b) {
    return (a + b);
};


A: Higher order functions (HOF) is just a fancy name for a function that accept a function as an argument or returns another function. If I understand you better, you are trying to create an adder function that can be used to add numbers. Using your example hof.add is an HOF that receives a function, and returns another function that can be used for adding two numbers together
 hof.add = function(add) {
  function addFunc(a, b) {
    return add(a, b);
  }
  return addFunc;
}

function add(a, b){
  return a + b
}

const addNumbers = hof.add(add);
addNumbers(3, 14)
//17 as answer
addNumbers can recieve any two numbers and it will add them together.

add is a function that adds two numbers together which is received as a parameter in hof.add. hof.add functions returns a function called addFunc who in turn receives two arguments to add together. Cheers

A: If you want to use only one argument-name, perhaps you meant to destructure it: function(...add)


const not_hof = {};

// Cheating by using destructuring (...add) 
// and not a HOF since accepts only Numbers as arguments 
not_hof.add = function(...add) {  
  const makeAdd = add.reduce((prev, curr) => {
    return prev + curr;
  }, 0);
  return makeAdd; // and still not a HOF since it returns a Number 
};

console.log(not_hof.add(2, 3));              // 5
console.log(not_hof.add(9, 1, 10));          // 20
console.log(not_hof.add(1, 1, 1, 1, 1, 1));  // 6


PS: The above function can be also expressed like:
not_hof.add = (...add) => add.reduce((prev, curr) =>  prev + curr, 0);

Not a HOF (higher order function)
Although many would say the above is a higher order function - since it returns Array.prototype.reduce, it's actually not:

Wikipedia - Higher order function
In mathematics and computer science, a higher-order function is a function that does at least one of the following:

*

*takes one or more functions as arguments (i.e. procedural parameters),

*returns a function as its result.


But add is not a procedural function argument; i.e:

procedure P(f):
 return f(2,3) * f(9,1)

and it does not return a function; rather a Number returned by Array.prototype.reduce.
1. HOF - One or more functions as arguments
To at least pass a function as argument:


const helper = { // Helper functions
  add(a, b) { return  Number(a) + Number(b); },
};


const hof = {};
hof.add = function(fn, add1, add2) { // HOF since it takes a function as argument
  return fn(add1, add2);             // (Returns a Number)
};

// ...But it takes three arguments
console.log(hof.add(helper.add, 56, 5)); // 61


2. HOF - Return a function
To at least return a function:


const hof = {};

hof.add = function(add) { // (Takes a Number argument)
  function makeAdd(b) {
    return add + b;
  }
  return makeAdd;         // HOF since it returns a function
};

// But accepts a single argument at each call
console.log(hof.add(56)(5)); // 61


or like


const hof = {};
hof.add = function(add1, add2) { // NOT LIKE YOUR EXAMPLE, 2 arguments are expected!
  function makeAdd() {
    return add1 + add2;
  }
  return makeAdd; // HOF since it returns a function
};

// ...The function had to be executed ()
console.log(hof.add(56, 5)());     // 61


but in such case it fails what your test states:

it('returns total of the two arguments', () => { // nope :( only one argument here...

HOF with closure
Allows to invoke the function multiple times with a Function.prototype.toString() in order to return at the last call the string


const hof = {};

hof.add = function(add) {
  let sum = add;    // Store in local scope
  const makeAdd = (b) => {
    sum += b;       // Access to lexical environment variables
    return makeAdd; // Returns a function (self)  
  }
  makeAdd.toString = () => sum;
  return makeAdd;   // HOF since we return a function
}

const result = hof.add(1)(2)(2)(56);
console.log(result)         // (f) 61
console.log(typeof result); // function
console.log(result == 61)   // true
console.log(result === 61)  // false
// A legitimate test might break since the strict equality operator fails.


Let's keep it simple. No closure, no HOF
If the first example using Array destructuring and Array.prototype.reduce() is not needed, than just stick to the simplest form of a function declaration:


const not_hof = {
  add: (a, b) => a + b,
  sub: (a, b) => a - b,
  // etc...
};

console.log(  not_hof.add(56, 5)  ); // 61


