Modern object-oriented JavaScript with ES6

Publish date:

Once a near-hegemonic paradigm in the world of application development, object-oriented programming (OO) has seen its cachet decline in recent years. The emergence of more functional-flavored or hybrid languages like Scala, Clojure, and Kotlin – not to mention JavaScript itself – is widely and rightly celebrated. Not every problem requires a lapidary, Aristotelian hierarchy of […]

Once a near-hegemonic paradigm in the world of application development, object-oriented programming (OO) has seen its cachet decline in recent years. The emergence of more functional-flavored or hybrid languages like Scala, Clojure, and Kotlin – not to mention JavaScript itself – is widely and rightly celebrated. Not every problem requires a lapidary, Aristotelian hierarchy of abstractions to solve!

Nevertheless, object-orientation remains the dominant paradigm for large applications and their underlying frameworks: its focus on code reuse via inheritance well serves the latter, and its data modeling approach is natural for software like simulations, UX toolkits, and enterprise logic.

Although the OO paradigm has always been possible in JavaScript, its use was obscured by the language’s unusual inheritance mechanism, confusing rules for object constructors, and lack of a native module system. The ECMAScript 6 standard eases these difficulties by defining new keywords (most of them being ‘syntactic sugar’ that translates to the older ECMAScript standard). In this post, we’ll explore these ES6 enhancements in the context of a classic OO use case: a user interface library. We’re going to build basic widgets for the Canvas API – let’s get started!

Considering the fundamental things any widget needs, we have a location, a bounding rectangle, a callback function to receive click events, and a render() method for the widget to draw itself. So we define the basic geometry, and a base Widget class:

The ‘class’ keyword, as in most languages, declares the start of a class – behind the scenes, it’s in fact declaring a function named Widget. A class’s constructor is simply named ‘constructor,’ and in this context, the reference ‘this’ behaves just like it does in Java or C++. But since this is JavaScript, we’re not obliged to declare our class members in advance; we can just make assignments to ‘this’ inside the constructor. Finally, notice the ‘export’ keyword at the end of each file: this is the new ES6 module system at work. Employing ‘export’ anywhere in a file automatically classifies it as a module. This means all declarations are in scope only within that file unless they’re explicitly stated as exportable. The particular syntax we’re using isn’t the only option; you can also modify data and function declarations with ‘export’.

Our basic Widget requires a Canvas’ graphics context to draw itself onto and a bounding rectangle to locate it on the screen. We also supply a callback for clicking it;  and a render() method, with a default fallback used if no renderer was given. Here’s how we use these modules in the browser:

Everything looks just as we expect from typical OO: we create object instances by writing the ‘new’ keyword before invoking a constructor. In the markup, the only unusual thing to note is the type attribute, ‘module’, on the inline <script> tag: this is required for inline scripts to use the ‘import’ feature.

So what other aspects of object orientation can we illustrate with this little widget model? Some inheritance would be nice. For differently shaped widgets, we’ll want different render() methods, and different ways to detect clicks. Prior to ES6, inheritance was done by manipulating the ‘prototype’ member that all objects inherently possess.

This is still how it works under the hood, but now we can use the convenient ‘extends’ and ‘super’ keywords:

Above, we’ve altered main() to instantiate a basic Widget, and one of its subclass, CircleButton. Let’s see the result of overriding the base implementation of render().

So that’s it – a whirlwind tour of all the basics of object orientation: encapsulation with scope-restricting modules, inheritance via subclassing, and overriding superclass methods. The story’s not quite finished here; ES6 also specifies a new keyword, ‘static,’ for declaring static (class) members, and shorthand keywords for declaring getters and setters too. We’ll talk about these and more in the next installment of this blog, where we’ll further explore object-oriented JavaScript by creating a simple game. Until then, happy ES6 coding!

Related Posts

Consumer

Pros and cons of differing distribution models

Lawrence Krasner
Date icon November 20, 2020

To meet the digital consumer from a marketing and lead generation perspective, the strengths...

agile

Eliminating work silos to drive business value in your customer experience programs

David Salguero Kuiters
Date icon October 16, 2020

Introducing Agile within your (digital) organization means that new processes, practices and...