Function Zoo

Function Zoo: Part 3 — Command, Overloading, Currying

Dmitry Yakimov
BeadList
Published in
3 min readNov 1, 2018

--

Part 1 — Part 2 — Part 3

This is the next article on function extensions. And today we are going to talk about command pattern and 2 arguments extensions: overloading and currying.

7. Command

Last time we compared function execution to a sending of a message. And we discussed that the objects name and the methods name are recipient address, and then the arguments is the body of a message.

Now with that in mind, we can also pass the methods name as anargument. Well, actually it’s pretty simple, it would work like this: let’s say we have a generic method send which accepts methods name and the rest of arguments. Then the code would look like this:

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'

This is called Command Pattern. This can be useful in many circumstances. When you are developing UI, it can be used for creating undo/redo buttons, when you want to log all the actions which has been called. Actually even Redux is based around command pattern as well.

Now with ES6 Proxy you can make command pattern look nicer:

const nextZoo = new Proxy(Zoo, {
get(target, propKey) {
console.log(propKey);
return target[propKey];
},
});
console.log(nextZoo.getColors());
// => getColors
// => [ 'Infra Red', 'Caribbean Green' ]

8. Overloaded Function

Function overloading is a way to enhance functions by allowing them to accept different types of arguments. And then dependent on the type of the argument it acts differently.

For example, let’s say we have a function which calculates squares of numbers, like this:

function numberSquare(number) {
return number * number;
}
console.log(numberSquare(2)); // => 4

Now if we would want to have a function which could also calculate squares each number of array, we could do it like this:

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 ]

In most cases I like to keep functions as simple as possible and I let them accept just one type of arguments. It is beneficial for minimizing maintenance costs and overall performance. So, generally function overloading is not recommended. Although in some cases it can be very useful, especially for recursive functions, when you destructure objects and arrays.

9. Curried Function

Curried functions were already discussed by everyone a lot. For people who missed it, basically curried functions allow to accept arguments one at a time. In a simple case it works like this:

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

Curried functions are nice and could be useful in rare cases. But generally they are just too much hassle to create, so it’s not very recommended to use them. They would be worthy though if they would be supported on the language level.

On this I conclude my series of articles on functions enhancement patterns. If anyone reads it, let me know if you have some other function types ideas.

Good luck with your coding adventures, folks! █

--

--

Dmitry Yakimov
BeadList

Web-consultant, Tech-enthusiast. Working on BeadList App: beadlist.com