Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Function-as-Object

DZone's Guide to

Function-as-Object

Martin Fowler provides insight into the function-as-object concept, which has been in place for some time, but has gained some traction in the JavaScript world.

· Web Dev Zone
Free Resource

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

In programming, the fundamental notion of an object is the bundling of data and behavior. This provides a common data context when writing a set of related functions. It also provides an interface for manipulating the data that allows the object to control access to that data, making it easy to support derived data and prevent invalid modifications of data. Many languages provide explicit syntax to define classes, which act as definitions for objects. But if you have a language with first-class functions and closures, you can use these constructs to create objects using the 'function-as-object' pattern (originally described by Eugene Wallingford).

Here is an example of a simplistic person object, done using the function-as-object style in JavaScript.

function createPerson(name) {
    let birthday;
    return {
        name: () => name,
        setName: (aString) => name = aString,
        birthday: () => birthday,
        setBirthday: (aLocalDate) => birthday = aLocalDate,
        age: age,
        canTrust: canTrust,
    };

    function age() {
        return birthday.until(clock.today(), ChronoUnit.YEARS);
    }

    function canTrust() {
        return age() <= 30;
    }
}

The outer form of a function-as-object is a function, which is called as a constructor function. The result of the call is, in essence, a hashmap of functions which acts as a method selector. This map captures the state of any variables in the function in a closure, allowing the data to persist beyond a single function invocation. This result hashmap can be treated like a classical object.

const kent = createPerson("kent"); 
kent.setBirthday(LocalDate.parse("1961-03-31")); 
const youngEnoughToTrust = kent.canTrust();

Looking at the function-as-object from a classical OO point of view:

  • The fields of the object are represented by the parameters to the constructor function (name)together with the local variables (birthday).
  • The methods of the object are the functions nested within the constructor function. Like object methods, they can freely call each other and manipulate the data in these locally scoped variables (fields).
  • Nothing outside the constructor function can access the variables, preserving data encapsulation.
  • The public methods of the object are those functions that are present in the result hashmap.
  • Any functions nested inside the constructor function, but not present in the result hashmap, are private methods.
  • The names of the public methods are the keys of the result hashmap, not the names of the functions within the constructor function. I prefer to keep the keys and function names the same to avoid confusion (although it can be handy to alias functions if needed).

A common alternative implementation of this pattern is to return a function as the method selector rather than the hashmap which is the natural method selector in JavaScript. To use a function as the method selector, I'd return a function whose first argument is the name of the method to invoke. The function body then switches on that value (see Wallingford for more on this).

The function-as-object approach has been around for a long time. I've seen it described in lisp many times, and it's been widely used in JavaScript (until ES6, JavaScript had a very limited notion of classes). It's often used as an argument that a specific syntax for classes isn't necessary, which is the equivalent of object-aficionados arguing that you don't need first class functions when you can write a class with a single "call" method. As a consequence, many people in the JavaScript world argue against using the ES6 class syntax. Personally, I like having both first class functions and first-class classes and prefer ES6's class syntax.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
javascript ,function ,object ,web dev

Published at DZone with permission of Martin Fowler, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}