Home Blog Index
Joseph Petitti —

Object-oriented functions in JavaScript

As you may know, JavaScript is a bit of an indecisive language. It doesn't fully commit to any one paradigm, instead having features from object-oriented, procedural, and functional languages. Its mish-mash of philosophies can make it confusing to learn, but once in a while it manages to surprise me with some clever design decision.

JavaScript uses prototype-based object orientation. This means that there are no "classes," but objects can inherit from other objects. Each object is simply an associative array between string keys and properties, which can be primitives or functions (like methods in other languages). They also inherit properties from their "prototype" object, which can be dynamically updated, changing all sub-objects.

But JavaScript has another powerful feature that many object-oriented languages lack: first-class functions. This means that functions are treated like first-class citizens: you can pass them as arguments to other functions, return them, and assign them to variables. This is a powerful paradigm that OO languages like Java still don't really support.

For example, first-class functions let you do stuff like filtering an array based on some condition very easily:

myArray.filter(function(value, index) { return (value % 2 === 0 || index > 5); });

This filters out odd numbers with an index less than or equal to 5 without having to implement or override anything.

First-class functions are neat, but what makes JavaScript functions really neat is that they are also objects. Functions can be declared like primitives (i.e. without using a constructor, kind of like Strings in Java), but they all inherit from the Function global object.

This means that functions have their own properties and methods. For example, you can use myFunction.apply() to change the this variable a function executes with. This is useful in all sorts of scenarios, and also opens up a lot of other interesting possibilities.

Because JavaScript objects are always mutable and inherit from other objects, you can make new objects that inherit from the Function object and implement new properties.

Unfortunately the Function constructor only operates in the global scope, and is therefore not super userful, you can still add new stuff to the Function prototype.

For example, if we wanted to implement function currying we could do it by adding a new method to the Function prototype.

Function.prototype.curry = function(...args1) { return (...args2) => this(...args1, ...args2); };

We use spread syntax and rest parameters to support partial application with multiple arguments at a time. We also use an arrow function to fit the whole body in one line.

Let's test it out:

function sum3(a, b, c) { return a + b + c; } sum3(1, 2, 3); // 6 sum3.curry(3)(5, 2); // 10 sum3.curry(1, 5)(6); // 12 sum3.curry(1); // Function

Now in practice you should avoid changing the prototype of any global object, but the ability to extend the Function object is a very powerful feature, and shows that despite all its weirdness JavaScript does have some good design choices.