Object-Oriented JavaScript: or Writing JavaScript the Way the Lord Intended

First, just kidding. For starters, I don’t really imagine the Lord much caring how we write JavaScript. But also,
what I’m going to describe is fairly dated. That’s because I want to show how to do reasonably isolated and
Object-Oriented JavaScript using nothing later than ECMAScript 5, which goes back 10 years at this point. There are
obviously better ways to do modular JavaScript available now, but to get backwards compatible and cross browser
support using those techniques usually require a transpiler (which usually translates your code back to ECMAScript
5), and creating the build chains that do that are a big leap for a novice, or old school, JavaScript developer.

And this being an old topic, there are many posts out there on this subject. but looking around, I couldn’t find one
that I liked. Or that emphasized what I felt was important. Just like a real programmer, not invented here, so I’m
writing my own.

Closures

In order to write reasonably encapsulated ECMAScript 5, you need to understand closures. And they’re not that hard
to understand, but are a bit difficult to describe. A closure is really just nested functions where the inner
function is exposed to (as in called from) something outside of it’s parent function. For example:

Here the innerFunc is called from outside of the outerFunc, which forms a closure. Before I get into why it’s significant that this
is a closure, there are other more subtle ways a closure can be formed. For instance:

Here, I have a nested anonymous function that I’ve assigned to document.ready.
I never execute it (in this code), but it is getting called, and when it is called it forms a closure. When the
document is ready, document calls the function. That’s all a closure is, a nested inner function that is called from
outside of it’s parent function, and hooking up event callbacks like this is really more the common case for
closures.

But why does it matter? Because when the nested inner function is called, the encapsulating outer function,
including any parameters or local variables, are restored to exactly the state they were in when the inner function
was created (not when it’s called, when it’s declared). That allows for some interesting consequences. Take, for
instance:

To which many people seeing this for the first time say “big whup, anyone who writes code like that should be shot,
I’ll never use it”. Not so fast sparky! Believe it or not, by itself this provides some interesting opportunities
for code reuse (hopefully when used for something a bit more substantial than multiplication). But combined with
other techniques we’ll talk about soon, it’s an important building block towards writing encapsulated
Object-Oriented JavaScript that doesn’t pollute the global namespace (much).

Immediately Invoked Function Expressions (IIFEs)

Well that’s a mouth full. Take the following code:

This is an IFFE. First there is an anonymous function:

Now declaring an anonymous function like this doesn’t make any sense. Nobody can call it, because nobody has a
reference to it. But in the IFFE above, the anonymous function is in parens, which tells JavaScript to execute
it immediately (which in this case means call the function immediately). So this function is going to be called
exactly once, immediately after it’s declaration. The second set of parens is where you can supply any arguments
to the invocation.

Again, big whup, right? But what this does is create a local scope, or closure. Take a look at the following:

First, what are x and y inside the
IFFE? y is a local variable, which you can tell because it is preceded by
var and inside a function. But local to what? For starters, it’s local to
the IFFE, which is really just a function. But also, any time the boring
function is called, it is local to the closure. x, on the other hand, is a
global variable. And if it existed and was in use by some other JavaScript, we’ve probably just stepped on that
JavaScript in a way that it didn’t anticipate, which may cause a JavaScript exception at some point down the
road. And those can be hard bugs to track down. So first rule: when in doubt use the var keyword, and declare as many variables as you can inside of closures to
avoid polluting the global namespace.

So what are x and y outside of the
IFFE, for instance when the function broken is called? Well x is still a
global, and in fact it’s value is still 5, because the IFFE was just executed a couple of lines before the
broken function is called. But y is
a problem. Here we’re using a global y, because we’re executing in the
global namespace. If a global y exists, and it’s a valid number, then the
broken function will run without error, but what it will do is not apparent from within this code. If it is
undefined or non-numeric, the broken function will throw an exception.

Let’s make a little alteration to our code that hopefully shows the significance a little better:

Here, x and y are both local, but
the boring function is global, meaning it can be called from outside of
it’s parent function and is thus a closure. When the boring function is
called outside of the IFFE, x and y
are still both 5. It doesn’t matter that in the runtime scope of the function call, x and y are 8 and 16 respectively. All
that matters is that when the function was declared, x and y are 5, and when it is called, inside the function, they are still 5 (or are
restored to 5 temporarily to be more accurate). That’s what defines the behavior of a closure, and allows for
some encapsulation inside of ECMAScript 5, a language that doesn’t have the concept of a Class, or
public/private access modifiers on object properties and methods.

So now that we know what an IFFE is, most, if not all, of the code I write from now on will be inside an IFFE.
Now we need to talk about namespaces.

Namespaces

You may have noticed that JavaScript doesn’t have a namespace keyword. In JavaScript, the concept of a namespace
is really just another object. So for instance, I create a namespace like so:

And now I’ll create another JavaScript file like so:

And in some other code I can do:

Here, I’m calling mynamespace.lessboring, which is in another JavaScript
file, and it works because we’re both using the global mynamespace. And it
in turn is calling mynamespace.boring, which also works because again
mynamespace is global. So z is equal to 5, or 5 * 5 / 5.

However, since I can pass parameters into my IFFE, there is an arguably better syntax to achieve this, so
rewriting just the last file as:

Here, my IFFE function takes in a parameter called ns, which is a nice
shorthand version of mynamespace that I can use locally to make my code
less bloated, but the longer name mynamespace is still used for the
global, making namespace collisions less likely. This sort of syntax is more common in ECMAScript 5 code that is
written like to be isolated and Object-Oriented JavaScript.

So second rule: use verbose names for namespaces to make collisions less likely, but there’s nothing wrong with
using a shorterhand name in you local scope to make the code less obtuse.

And third rule: you can write an arbitrarily complex JavaScript application without ever putting more than one
variable in the global namespace. And you should. Everything hangs off your namespace object. If your program is
so complex that the right hand doesn’t know what the left hand is doing, so you feel like you need more than one
namespace, use sub-namespaces. Like mynamespace.team1 and mynamespace.team2, and the above function could be mynamespace.team1.lessboring. Locally, you can still assign it to something
shorter to keep your code lean.

Putting the Object back in Object-Oriented JavaScript

So I’ve been talking quite a bit about Object-Oriented JavaScript, but I haven’t actually talked much about
objects. We’re going to remedy that now, but this should be fairly short because the boiler plate stuff of been
covering up to now is a lot of the heavy lifting. There are basically two styles of object syntax in JavaScript,
which I’ll cover in the next two sections.

Classic Constructor Objects

In classic Object-Oriented JavaScript, an object is created from a constructor, which is really just a function.
So here I have a function called mynamespace.Connection, which constructs
objects:

To instantiate an instance, I just call new on that function and pass in a url:

JavaScript objects have prototype inheritance, so any functions attached to the prototype of my constructor will
be available as a method of the object created by my constructor. However, if an instance is created and then
later a method is added to the prototype, the existing instance isn’t modified in any way, and only new
instances will have that method.

And there is a potential problem with the above implementation. Consider the following usage:

In this case, connect is called as an event callback from document.ready. So inside the connect
method when it access this.url, that will lead to a bit of a let down.
Because this now points to document,
not mynamespace.Connection.

To get around this, you can rewrite the constructor like so:

Now, the connect method is embedded within the constructor. It can take
advantage of that. The constructor can make a copy of this in the local
variable self, which the connect
method can count on and use to access self.url. Why? Because it’s in a
closure.

Object Literals

We’ve already seen object literals, when we looked at namespaces. In it’s simplest form:

The open/close curly braces describe an empty object literal. Object literals can be useful for creating
singletons, object instances that there logically should be only one of throughout an application. So:

This looks a lot like JSON. You can declare properties and methods, each being a name colon value, and separated
by commas. And with this syntax, I do need to save off this, because I can
always use ns.Connection to get to my properties without having to worry
about the context of this.

So which is better? I’ve now defined mynamespace.Connection each way, so
which should we choose? Naturally, it depends. The object literal notation is a little easier on the eyes for
me, but I can instantiate as many times as I want with the constructor syntax. Generally, if I’m confident I’ll
only need one instance of an object, I’ll do the object literal notation. Otherwise, the constructor notation.

The Complete Example

And many of the tutorials I saw weren’t very satisfactory to me because they provided no realistic examples.
With only goofy examples like multiplyByX, it’s hard to determine if it’s worth it. My complete example is based
off of Tutorial:
Azure SignalR Service authentication with Azure Functions
(Note: this code is from the first part of the tutorial,
before authentication was implemented). That tutorial used ViewJS, which I thought
was pretty dumb, so I stripped that out for plain JavaScript. Nothing against ViewJS, but a starter tutorial on
SignalR shouldn’t require me to also know a particular UI framework (thanks a bunch Microsoft).

Anyway, it’s a simple chat client allowing multiple people to connect to SignalR and do a group chat in the
browser. Here is the HTML:

And here is a wrapper for the SignalR functionality, done as a singleton object literal:

And finally, here is the main entry point for the JavaScript done as a classic JavaScript object:

Note that this second JavaScript file doesn’t actually expose anything through the namespace. It doesn’t need to
because it just sets up some event callbacks and takes advantage of a closure. It does use the namespace, but
just to access the SignalR wrapper instance.

Even if your not an Azure guy or don’t have access to SignalR, I think the example is simple enough to get the
idea.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.