назад до уроку

Сума з довільною кількістю дужок

важливість: 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 для конверсії.

Відкрити рішення із тестами в пісочниці.