Есть забавный вопрос (в зависимости от вашего определения веселья, конечно 😆). Как написать функцию 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.
Меня зовут Алексей Комов - интерфейсный разработчик и веб-энтузиаст, интересующийся основными и конкретными веб-вещами. Поделитесь своими мыслями по поводу статьи. И вы можете связаться со мной здесь.