Есть забавный вопрос (в зависимости от вашего определения веселья, конечно 😆). Как написать функцию sum, чтобы верно следующее?

sum(1) == 1;//true
sum(1)(2) == 3;//true
sum(1)(4)(1) == 6;//true
/*And works on any number of curried calls, adding numbers from each call.*/

Прокомментируйте здесь свои решения. :) Если вы не уверены (как я, когда впервые спросили об этом 🤔) или вам интересно, читайте дальше.

Обратите внимание на две важные части: как мы проверяем равенство результата функции (с ==) и как каждый результат вызова sum вызывается сам. Из пункта два очевидно, что каждый результат вызова суммы - это сама функция.

Из стандарта ECMAScript мы знаем, что когда оператор == выполняется над значениями двух разных типов, оба они приводятся к числу. Правая рука - это уже число, а левая рука (которая является функцией), очевидно, будет NaN. Вы можете проверить это явным преобразованием в число:

+function(){};//NaN 

Итак, подобные тесты эквивалентны

sum(1) == 1;//true
sum(1)(2) == 3;//true
sum(1)(4)(1) == 6;//true
+sum(1);//1
+sum(1)(2);//3
+sum(1)(4)(1);//6

И как нам переопределить это поведение «до NaN» и вернуть любое значение, которое мы хотим? Путем реализации нашего собственного valueOf. Итак, теперь, по крайней мере, эта часть ясна:

Хорошо, теперь он работает с

sum(1) == 1; 

состояние по крайней мере. А как нам реализовать newFunction сверху?

Для цепного звонка мы хотим вернуть саму сумму. Но если бы мы сделали это

const newFunction = sum;

, результатом каждого связанного вызова будет возвращенный аргумент firstArgument, а не сумма.

Итак, давайте обернем сумму функцией, которая принимает аргумент и вызывает сумму с этим новым аргументом + старым аргументом firstArgument из основной функции суммы.

Хорошо, давайте протестируем эту реализацию.

+sum(1)
1
+sum(1)(2)
3
+sum(1)(2)(3)
6

Выглядит нормально!

Те из вас, кто хочет найти решение, могут придерживаться этого ✋. Но если вы хотите уточнить детали, читайте дальше.

Ладно, честно говоря, мне не очень нравится предыдущее решение. Как насчет этого?

Здесь мы передаем стек всех накопленных аргументов в рекурсивный вызов. А в вызове valueOf стек преобразуется в число с помощью сокращения точно во времени. Это дает нам больше гибкости, imo, если мы хотим заменить цепную сумму на цепное умножение или что-то еще - мы просто подключаем другую функцию сокращения.

Ладно, на этот раз все наверняка 😂. Cya.

Меня зовут Алексей Комов - интерфейсный разработчик и веб-энтузиаст, интересующийся основными и конкретными веб-вещами. Поделитесь своими мыслями по поводу статьи. И вы можете связаться со мной здесь.