Зоопарк функций: часть 3 — команда, перегрузка, каррирование
Это следующая статья о расширении функций. И сегодня мы поговорим о паттерне команды и расширениях с двумя аргументами: перегрузкой и каррированием.
7. Команда
В прошлый раз мы сравнивали выполнение функции с отправкой сообщения. И мы обсуждали, что имя объекта и имя метода — это адрес получателя, а затем аргументы — это тело сообщения.
Имея это в виду, мы также можем передать имя метода в качестве аргумента. Ну, на самом деле это довольно просто, это будет работать так: допустим, у нас есть общий метод send
, который принимает имя метода и остальные аргументы. Тогда код будет выглядеть так:
const Zoo = { // Regular methods getAnimal(type, color) { const animals = { Frog: { 'Infra Red': 'ir_frog.jpg', 'Caribbean Green': 'cr_frog.jpg', }, Fish: { 'Infra Red': 'ir_fish.jpg', 'Caribbean Green': 'cr_fish.jpg', }, }; return animals[type][color]; }, getColors() { return ['Infra Red', 'Caribbean Green']; }, getTypes() { return ['Frog', 'Fish']; }, send(methodName, ...arguments) { return this[methodName](...arguments); }, }; console.log(Zoo.send('getTypes')); // => [ 'Frog', 'Fish' ] console.log(Zoo.send('getAnimal', 'Fish', 'Infra Red')); // => 'ir_fish.jpg'
Это называется Шаблон команды. Это может быть полезно во многих случаях. Когда вы разрабатываете пользовательский интерфейс, его можно использовать для создания кнопок отмены/возврата, когда вы хотите регистрировать все действия, которые были вызваны. На самом деле даже Redux также основан на шаблоне команд.
Теперь с ES6 Proxy
вы можете сделать шаблон команды более красивым:
const nextZoo = new Proxy(Zoo, { get(target, propKey) { console.log(propKey); return target[propKey]; }, }); console.log(nextZoo.getColors()); // => getColors // => [ 'Infra Red', 'Caribbean Green' ]
8. Перегруженная функция
Перегрузка функций — это способ улучшить функции, позволяя им принимать различные типы аргументов. И затем в зависимости от типа аргумента он действует по-разному.
Например, предположим, что у нас есть функция, которая вычисляет квадраты чисел, например:
function numberSquare(number) { return number * number; } console.log(numberSquare(2)); // => 4
Теперь, если бы мы хотели иметь функцию, которая также могла бы вычислять квадраты каждого числа массива, мы могли бы сделать это следующим образом:
function arraySquare(array) { return array.map(numberSquare); } function square(numberOrArray) { if (Array.isArray(numberOrArray)) return arraySquare(numberOrArray); else return numberSquare(numberOrArray); } console.log(square(2)); // => 4 console.log(square([1, 2, 3])); // => [ 1, 4, 9 ]
В большинстве случаев мне нравится делать функции как можно более простыми, и я позволяю им принимать только один тип аргументов. Это выгодно для минимизации затрат на техническое обслуживание и общей производительности. Таким образом, обычно перегрузка функций не рекомендуется. Хотя в некоторых случаях это может быть очень полезно, особенно для рекурсивных функций, когда вы деструктурируете объекты и массивы.
9. Каррированная функция
Каррированные функции уже много обсуждались всеми. Для тех, кто пропустил это, в основном каррированные функции позволяют принимать аргументы по одному. В простом случае это работает так:
function multiply(a, b) { if (b) return a * b; return function(b) { return a * b; }; } const double = multiply(2); console.log(multiply(2, 3)); // => 6 console.log(multiply(2)(3)); // => 6 console.log(double(3)); // => 6
Каррированные функции хороши и могут быть полезны в редких случаях. Но, как правило, их слишком сложно создавать, поэтому не рекомендуется их использовать. Но они были бы достойными, если бы их поддерживали на уровне языка.
На этом я завершаю серию статей о паттернах расширения функций. Если кто-нибудь прочитает это, дайте мне знать, если у вас есть идеи о других типах функций.
Удачи в ваших приключениях по программированию, ребята! █