JavaScript Fanboi


How I Became a JavaScript Fanboi

Embracing the reality that this little language has a lot to offer

by Joe Honton

As a software developer with decades of professional experience, I've worked with lots of languages. Naturally I've formed opinions about each of them.

Perhaps inevitably, those opinions have evolved as I've moved past the syntax, and began to grasp the gestalt of each language — their innate ability to express solutions to problems.

JavaScript is a case in point where I initially got it all wrong.

Before sharing my story, permit me to mention the projects I've been working on, as a personal testament and proof of what's possible with today's JavaScript:

  • A compiler for a new type of Markdown being a complete lossless expression of HTML.
  • A static HTTP/2 web server, akin to Apache or nginx, purpose-built for JavaScript backends, with compression, caching, content negotiation and CORS.
  • Electron Desktop Apps for declarative templating and content authoring.
  • DOM Components using W3C custom elements and shadow DOM.
  • Dynamic Plugins for working with the HTTP request/response cycle without middleware.
  • CLI Tools for building better software.

Taken one-by-one we could shrug our shoulders, but taken together the range of possibilities is an impressive feat for a single language.

The Language

What I once considered to be a toy language suitable for scripting, I now consider to be a first rate language for general purpose computation.

From its inception to its current state, the transformation has been dramatic. Initially it was designed as a domain-specific language to allow browsers to manipulate HTML. But it has transformed itself into a general purpose language available on servers, desktops, cell phones, embedded controllers, and tiny system-on-a-chip devices.

Considered in terms of isolation, the language no longer suffers from global variable pollution. Instead, it allows variables to be named and used without clashing in a wide variety of contexts:

  • Simple functions, where the function can only access its arguments and its locally defined variables.
  • Functions within functions (closures), which allow the inner function to have full access to the outer function's variables.
  • Functions as arguments (callbacks), where the callback is invoked by the receiving function to perform work on its behalf.
  • Object methods, where the function has full access to all of the properties of its class-based object.
  • Bound functions, where the stack's "this" pointer is overridden, guaranteeing independence from the caller's context.
  • Namespaced functions (static functions of a class), where the function acts as a simple function which can only be accessed through its class name.
  • Iterable functions (generators), where the variables maintain their state from one invocation to the next.

And consider the simplicity of the built-in data types and their seemingly limitless range of values.

  • Maps, Sets, Arrays, and Objects have generous support for very large collections, and very few apps ever bump into their ceiling before exhausting the computer's virtual memory limits.
  • Numeric value can be as large as 9 007 199 254 740 991 and as accurate as 0.000 000 000 000 000 01. And the built-in Math object has the full set of trigonometric and logarithmic functions, allowing the language to be applied to serious numerical problems.
  • BigInt objects allow integer arithmetic to be performed on arbitrarily large values.
  • ArrayBuffer and TypedArray allow direct access to heaps on a byte-by-byte basis, making image manipulation a possibility.
  • Literal values can be expressed in binary (0b1111) and octal (0o17) as well as their more familiar decimal (015) and hexadecimal (0xF) forms.
  • Bitwise operations are available in full: AND, OR, XOR, NOT, left shift, signed right shift, and zero fill right shift.

Organizationally, the language allows for grouping things into objects and classes and modules, allowing large problems to be decomposed into manageable pieces.

Code execution is non-preemptive, allowing the developer to know with certainty that any function will run from start to finish without interruption, freeing the developer from worry that other functions may change data that it is working on.

When long-running tasks are scheduled, the developer can use promises with async/await to simulate concurrency while retaining the guarantees that come with JavaScript's non-preemptive model. And when developing outside the browser, Node.js has worker threads can be used to simultaneously access multiple CPUs when needed.

All told, the possibilities are now far beyond what they initially were back in 1995.

The Community

We owe this happy state of affairs to the hard work of the standards committee, the compiler makers, the package distributors, and the library developers.

Some people may not know that the name "JavaScript" is not the official name for the language: it's ECMAScript. The formal standard for the language is defined by the ECMA-262 specification, published by Swiss-based Ecma International.

Ecma International's technical committee TC39 is the vibrant side of the standard. This is the group that meets regularly to decide what new features to add to the language, what precise syntax to use, and what algorithm to follow to implement those features. The blitz of new features we've witnessed since 2015 is due to the tech wizards — from many of the world's biggest tech companies — who work on this committee.

But specifications are just the first step. It's the parsers, interpreters, and compilers that make it possible for us to put those new features to use. The V8 just-in-time compiler is the industry's darling, so kudos to the team at Google for such a high-performance engine. But we can't safely use a new JavaScript feature until every browser has it, so the work on SpiderMonkey (Mozilla), JavaScriptCore (Apple), and Chakra (Microsoft Edge Legacy) must be acknowledged as well.

Then there's the library and framework developers who have given us ready-made solutions for so many things: database connectivity, SMTP mailers, WebSockets, and data visualization to name just a few; plus excellent tools to make the software development craft even better: beautifiers, linters, validators, and testers.

Finally, there's NPM. What can I say? It's one of the most popular package managers for any language ever. To say that NPM has contributed to the success of JavaScript is an understatement.

The bottom line is simply this: the JavaScript community is strong.

From Doubter to Fanboi

My first humble JavaScript function was deployed to production in 1999. It was an onClick function for search engine optimization (SEO) that I called nomojo, because it kept Google PageRank from sending juice to external hyperlinks. At the time, onClick handlers were pretty much state-of-the-art.

Shortly after, the JavaScript interface to the nascent Document Object Model (DOM) began showing up in browsers. It was a messy affair, complicated by vendor intransigence and finger pointing. A routine part of my work was writing and maintaining my own compatibility layer for basic stuff like event listeners and AJAX. It was a tedious effort: testing each change, on every browser, on every operating system combination.

Like most developers at that time, I had no confidence that JavaScript or DOM would amount to much. But slowly, thanks in part to the near universal adoption of jQuery as the compatibility layer, DOM programming shed its niche status and became mainstream.

Yet it was hard to take the language seriously when every variable was global by default. It wasn't until strict mode became widely available in 2012 that developers could safely localize their variables with certainty using var.

Still, as recently as 2014, I was turning down offers to work with JavaScript. The community hadn't yet agreed on how to modularize things, so competing efforts to graft something as fundamental as modules onto the language in userland made all of us look foolish.

But 2015 was a watershed year for JavaScript. That was the year that TC39's newest batch of features landed in browsers. It signaled the start of a new era. Every year since, the community (TC39 committee, compiler makers and browser vendors) has pushed out new features in juggernaut fashion.

For me, the writing was on the wall: 2015 was the year that I registered the domain name and began using it as my professional portfolio gateway.

Fast forward to 2020. In January, one of the remaining critical pieces finally became usable when Microsoft deployed its flagship Edge browser using the Chromium WebKit based engine. JavaScript modules via script tag, on the caniuse website, lit up green across all of the major browsers, signaling that import and export were good to go without a transpiler.

And with that latest piece of the puzzle in place, I became a self-acknowledge JavaScript fanboi.

Finally, allow me to close with a parting thought and encouragement to everyone out there hoping to find the next great programming language. Here's a tip: it's right in front of you, and it's not going away any time soon.

How I Became a JavaScript Fanboi — Embracing the reality that this little language has a lot to offer