skip to Main Content
console.log(sum(1)(2)(3));  // -> 6
console.log(sum(3)(15));   // -> 18 

function sum(a) {
  let currentSum = a;

  function f(b) {
    currentSum += b;
    return f;
  }
  f.toString = function() {
    return currentSum;
  };
  return f;
}

This function adds the arguments that are passed to it, and after all additions the string currentSum is returned. I don’t really understand how the conversion to a primitive occurs and why write it through a function

2

Answers


  1. The default toString function of a Function will return the stringified function. To display the (intermediate, enclosed) currentSum value of f, you need to override that toString function. Maybe this snippet clarifies this:

    function sum(a) {
      let currentSum = a;
    
      function f(value = 0) {
        currentSum += value;
        return f;
      }
      
      f.toString = function() {
        return currentSum;
      };
      
      return f;
    }
    
    function someFunction() {
      return 1;
    }
    
    // a functions default 'toString'
    console.log(`${someFunction}`);
    
    const six = sum(1)(2)(3);
    // six is a function
    console.log(`const six = sum(1)(2)(3);
    typeof six: ${typeof six}`);
    
    // toString (of the function) is automatically 
    // invoked within a template string
    console.log(`current value of six: ${six}`);
    
    // change [currentSum] (six is still a function)
    console.log(`typeof six(10): ${typeof six(10)}`);
    
    // the value of six has changed
    console.log(`current value of six: ${six}`);
    .as-console-wrapper {
        max-height: 100% !important;
    }

    For fun: because a Function is just another Object, you can also extend it with your own ‘value’ method. In that case you have to explicitly call the extension method(s) to retrieve the enclosed value.

    function sum(a = 0) {
      let currentSum = a;
    
      const f = (value = 0) => {
        currentSum += value;
        return f;
      }
      
      // extend
      f.value = _ => currentSum;
      f.reset = _ => { currentSum = 0; return f; }
      f.increment = _ => { currentSum += 1; return f; }
        
      return f;
    }
    
    const six = sum()(1)(2)(3);
    console.log(`six.value(): ${six.value()}`);
    console.log(`six(10).value(): ${six(10).value()}`);
    console.log(`six.increment().value(): ${six.increment().value()}`);
    console.log(`six.reset().value(): ${six.reset().value()}`);
    console.log(`six(1)(2)(3).value(): ${six.reset()(1)(2)(3).value()}`);
    .as-console-wrapper {
        max-height: 100% !important;
    }

    One step further may be to convert the methods to getters (so you don’t need parentheses using them), or add your own setters to the function:

    function sum(a = 0) {
      let currentSum = a;
    
      function f(value = 0){
        currentSum += value;
        return f;
      }
      
      const extensions = {
        get value() { return currentSum; },
        set value(val) {currentSum = val; return f; },
        get reset() { currentSum = 0; return f; },
        get increment() { currentSum += 1; return f; },
      };
      
      Object.entries(Object.getOwnPropertyDescriptors(extensions))
        .forEach( ([key, descriptor]) => { 
          Object.defineProperty(f, key, descriptor); 
        } );
      
      return f;
    }
    
    const six = sum(1)(2)(3);
    console.log(`native six.toString(): ${six}`);
    console.log(`six.value: ${six.value}`);
    console.log(`six(10).value: ${six(10).value}`);
    console.log(`six.increment.value: ${six.increment.value}`);
    console.log(`six.reset.value: ${six.reset.value}`);
    console.log(`six.increment(2)(3).value: ${six.increment(2)(3).value}`);
    six.value = 12;
    console.log(`six.value = 12;
    six(30).value: ${six(30).value}`);
    .as-console-wrapper {
        max-height: 100% !important;
    }
    Login or Signup to reply.
  2. Q&R:
    -1- what is sum() ?
    in JS everything is an Object (even if they are defined as a function).

    -2- what is currentSum ?
    it is a local value inside sum().
    this local value can only be changed inside the scope of sum().

    -3- what is f ?
    an object function which add his argument value to currentSum
    and return itself (a function)

    -4- what is f.toString ?
    it is an overloading method on the f object
    it overload the deault Object.prototype.toString() (javascript is a prototype object model)

    -5- what happend in console.log(sum(1)(2)(3)); ?
    there is differents step :

    __a) let fctA = sum(1) -> currentSum = 1, and return f see sum()’s last line
    __b) let fctB = fctA(2) -> currentSum += 2 and return f
    __c) let fctC = fctA(3) -> currentSum += 3 and return f
    __d) let D = fctC.toString() => call the toString() method of f.

    let fctA = sum(1);
    let fctB = fctA(2);
    let fctC = fctA(3);
    let D = fctC.toString();
    
    console.log( D );
    
    function sum(a)
      {
      let currentSum = a;
      function f(b) 
        {
        currentSum += b;
        return f;
        }
      f.toString = function()
        {
        return currentSum;
        };
      return f;
      }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search