вернуться к уроку

Сумма с произвольным количеством скобок

важность: 2

Напишите функцию sum, которая бы работала следующим образом:

sum(1)(2) == 3; // 1 + 2
sum(1)(2)(3) == 6; // 1 + 2 + 3
sum(5)(-1)(2) == 6
sum(6)(-1)(-2)(-3) == 0
sum(0)(1)(2)(3)(4)(5) == 15

P.S. Подсказка: возможно вам стоит сделать особый метод преобразования в примитив для функции.

  1. В общем, чтобы это хоть как-нибудь заработало, результат, возвращаемый sum, должен быть функцией.
  2. Между вызовами эта функция должна удерживать в памяти текущее значение счётчика.
  3. Согласно заданию, функция должна преобразовываться в число, когда она используется с оператором ==. Функции – объекты, так что преобразование происходит, как описано в главе Преобразование объектов в примитивы, поэтому можно создать наш собственный метод, возвращающий число.

Код:

function sum(a) {

  let currentSum = a;

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

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

  return f;
}

alert( sum(1)(2) ); // 3
alert( sum(5)(-1)(2) ); // 6
alert( sum(6)(-1)(-2)(-3) ); // 0
alert( sum(0)(1)(2)(3)(4)(5) ); // 15

Пожалуйста, обратите внимание на то, что функция sum выполняется лишь однажды и просто возвращает функцию f.

Далее, при каждом последующем вызове, f суммирует свой аргумент со значением currentSum и возвращает себя же.

В последней строке f нет никакой рекурсии.

Вот как выглядит рекурсия:

function f(b) {
  currentSum += b;
  return f(); // <-- рекурсивный вызов
}

В нашем случае мы просто возвращаем функцию, не вызывая её:

function f(b) {
  currentSum += b;
  return f; // <-- не вызывает себя. Просто возвращает
}

Функция f будет использоваться в последующем вызове и снова возвращать себя столько раз, сколько будет необходимо. Затем, при использовании в качестве числа или строки, метод toString возвращает currentSum – число. Также здесь мы можем использовать Symbol.toPrimitive или valueOf для преобразования.