Because its been a while since we focused on JavaScript, the bulk of this instalment will focus on solving the challenge set at the end of the previous instalment. We’ll work through the solution in detail, step-by-step.

We’ll finish the instalment by making a start on moving from JavaScript version 5, to JavaScript version 6, or ECMAScript 6, usually just called ES6. When we started our look at JavaScript about a year and a half ago it made sense to use JavaScript 5, but now it’s time to upgrade our knowledge. ES6 was a very big change indeed, so we won’t bit it all off at once. Instead, we’ll focus on just one very important change in this instalment — ES6’s new take on variables.

There’s no zip file for this instalment as such, instead, I’ve published my sample solution as a tagged release on GitHub instead. You can use the big green clone or download button to either copy the code using GIT, or download it as a ZIP file.

PBS 42 Challenge Sample Solution

The starting point for the challenge was a working initial version of the Cellular Automata prototypes, and web app (HTML page) that uses those prototypes to implement Conway’s Game of Life. The only UI on the page was a single button to move the CA one step forward.

Part 1 — An Automatic Step Mode

The first part of the challenge was to add an automatic mode to the page so the user can click a button to start the Game of Life running, and it should then keep running until the user stops it.

This features is not in any way specific to the game of life, but something you’d want to be able to do to any CA, so it makes sense to add the functionality into the prototypes rather than into the Game of Life web app.

There’s no single correct way to implemented an automated mode like this, but two obvious options spring to mind — an interval that calls the .step() function repeatedly, or, a recursive timeout that calls the .step() function and then calls itself again. (For documentation on both see MDN’s article on JavaScript Timers).

This is one of those situations where the is no obvious right answer, both an interval and a recursive timeout can be made to work, and indeed, to work well. It comes down to preference really.

When you take into account the fact that as well as starting and stopping the automation we also want the ability to control its speed, our two options boil down to the following big-picture algorithms:

For an interval:

  • The start button starts a new interval and saves the ID
  • The stop button cancels the interval and blanks the ID
  • Changing the speed cancels the interval and then re-starts it with new settings and saves the new ID

For a recursive timeout:

  • The start button sets a flag to indicate automatic mode is active, takes a step, then sets a timeout (based on the current speed) that calls a helper function which does the following:
    • Checks the auto-run flag, if not present, does nothing
    • If the auto-run flag was present it sets a new timeout to call itself with the delay being based off the currently selected speed.
  • The stop button removes the auto-run flag — the next time the timeout executes it will do nothing, so execution will stop
  • Changing the speed doesn’t require any action — the next time the timeout executes it will use the new speed automatically

There is no right answer, it’s purely down to preference. I like recursion, so I consider the second option easier, so that’s what I chose. Many of you probably made the other choice. As long as your code works, no problem!

Regardless of which approach you chose, the ultimate goal will be to add two functions to the bartificer.ca.Automaton prototype, .start() and .stop().

Before implementing those two functions I added two new private instance variables to the prototype:

  1. A simple flag to keep track of whether or not the CA is in automatic mode
  2. The number of milliseconds to pause between automatic steps

Like the other instance variables that already exist in the prototype, these variables will be initialised within the constructor:

When ever we add new functionality we should add matching tests to our test suite, so, let’s do that by adding the following two assertions to the bottom of the ‘bartificer.ca.Automaton prototype > constructor: argument processing’ test:

Our .start() and .stop() functions will take care of the value stored in ._autoStepID, but we need to provide a public accessor function for the delay between automatic steps (._autoStepMS).

I’v chosen to store the delay between automatic steps as a whole number of milliseconds, so before we write the public accessor we should create a private validation function to test if an arbitrary value is valid as a delay:

We’re now ready to add the accessor:

Again, we’ve added new functionality to our prototype, so, we need to update our test suite. This time by adding a whole new test:

Now that we have the instance variables and accessors we need to store the data that will control our automatic mode, we’re ready to implement it. Let’s start with the .start() function::

This function is perhaps surprisingly short, but because it contains recursion, it might make your brain hurt a little. Yes, the autoStepFn callback does indeed call itself, assuming automatic execution hasn’t been cancelled.

We can now test our new function by opening sample.html in our browser, enabling the developer tools, and entering sampleCA.start() in the console. That should start the game of life going, stepping forward twice a second. We haven’t written a stop function yet, so the only way to stop it for now is to refresh the page!

So, let’s resolve that obvious shortcoming by implementing .stop():

Our prototype now has the ability to run automatically, but we have no UI to allow the user to control it yet.

Let’s start with the HTML:

And now let’s add event handlers (within the document ready handler):

If you refresh sample.html you’ll see that we now have working play and stop buttons.

Part 2 — A Generation Counter

The second part of the challenge was to implement as counter showing the current generation of the automaton (each step is a generation).

The first step is obviously to add another instance variable to the bartificer.ca.Automaton prototype to store the generation count. Again, initialised in the constructor:

Like before, we should add a test case to the bartificer.ca.Automaton prototype > constructor: argument processing test:

We also need a read-only accessor function for this value:

Again, we need to add a test for this function to our test suite:

At this stage we have a variable for holding our generation count, and, a function for accessing it, but we’re not yet actually counting the generations! Clearly, we need to increment the counter when ever we move from one step to the next, and, we need to set it back to zero when ever we re-set the automaton to a fresh state.

To do that we need to add the following line to bartificer.ca.Automaton.prototype.step():

And, the following to bartificer.ca.Automaton.prototype.setState():

We should now add a test to verify that generation counting is working as expected:

Now that our prototype can count its generations, how do we show that count in the UI?

A good prototype is generic and re-usable, so we absolutely don’t want to hard-code the counter UI into the bartificer.ca.Automaton prototype. What we need is functionality to allow developers using the prototype to pass the the prototype a callback that the prototype will then promise to execute each time the generation changes. In other words, we need to add basic support for events.

Let’s start by adding another instance variable to the bartificer.ca.Automaton prototype to store a reference to the function to execute when ever the generation changes. Mind you — why only add support for a single callback? Why not allow developers to add as many listeners as they like to our generation change event? How? With an array!

As with all other instance variables, we need to initialise this new variable within the constructor:

Again, we should update the test for our constructor to make sure this variable gets properly initialised by adding the following assertion:

Now we need to write a function for adding callbacks into our array. Given that our prototypes rely on jQuery, it probably makes sense to copy jQuery’s convention when it comes to event handlers, and have the function add an event handler when passed a callback, and execute all currently registered callbacks when called with no parameters (like .click() etc.):

All we need to do now is call our new function with no parameters from within both the .step() and .setState() functions:

Now that we have this functionality implemented, we need to add a test for it to our test suite:

Now that we have an event handler at our disposal we can add a generation counter to our UI. First, we’ll need to add some simple HTML markup:

Then, we need to add an event handler to our new generation change event by adding the following to the page’s document ready handler:

Part 3 (for extra credit) — Variable Speed

The final, optional, part of the challenge was to add a control to the UI to allow users to vary the speed of the automatic mode. IMO a slider seems like the most intuitive UI for this kind of functionality, so that’s how I choose to do it. You could just as well have chosen a numeric field, a radio button group, or even a drop-down menu.

I chose to have my slider represent the speed in frames per second, that way sliding right increases the speed. Here’s the HTML markup for my slider:

All that remains to be done at that stage is to add an event handler to this slider that converts frames per second into the number of milliseconds to pause between steps, and then sets the auto-execution timeout appropriately (again, within the document ready event handler):

A Few Other Tweaks

While I was editing the code I chose to make a few other cosmetic changes to my game of life implementation. Specifically, I added some CSS to the table representing the automaton to collapse the spacing between the cells, add a border around the automaton as a whole, add a small margin, and shrink the cells so I could make a bigger automaton:

To get more cells I simply altered the call to the constructor:

With the cells touching directly the patterns became more visible, but the red and green became utterly over-powering, so I change the render function to render dead cells in a lighter shade of red:

Finally, when I started to really play with the Game of Life I found myself wanting a button to re-seed the game to a fresh random state, so I added a button for that:

With a matching event handler:

The finally version of this code with all the changes mentioned is published on GitHub as a tagged release.

Introducing JavaScript ES6 (EMAScript Version 6)

When we started our exploration of JavaScript back in instalment 12 I had to make a decision — what version of JavaScript should we use? ES6 was out, but browser support was patchy at best, so I chose to stick with the previous version — ECMAScript 5. So, all the JavaScript you’ve seen in this series to date has been ES5.

Well — a year and a half is a long time in tech, so things have moved on. ES7 is now the new kid on the block with the patchy support, and ES6 is now well supported in all modern browsers. So, I think the time has come to embrace ES6, and to abandon some old practices. ES6 was a very substantial upgrade to the language, so it’s going to take us a few instalments to make the transition.

Good Bye var, Hello let & const

IMO, the most significant change brought by ES6 is a complete re-think on scope, bringing JavaScript into line with just about every other language I’ve ever used. For backwards compatibility reasons, the old behaviour is not going away, but you can choose not to use it anymore by abandoning the var keyword. In ES6, when you use var, the old rules apply, any when you use either of the new declaration keywords (let & const), the new rules apply. In very rare occasions you may actually want the old behaviour, in which case you should make the conscious decision to use var, but 99.9% of the time you almost certainly don’t want to do that.

What’s Wrong with var?

JavaScript is generally described as being a a C-style language. Indeed, JavaScript is very C-like in many ways, but the big exception is variable scope.

Pre-ES6 JavaScript uses function scope — i.e., when you declare a variable, it exists within the function it was declared within. The other C-style languages have a narrower concept of scope — variables exist within the code block they’re declared within (block scope). In other words, each time you group one or more statements together within curly braces, you create a new scope.

ES6 moves JavaScript into line with the norm by moving from function scope to block scope. For backwards compatibility reasons, the change is not total. ES6 lets us have our cake and eat it by adding two new variable declaration keywords — let and const.

If you use var, you get a function-scoped variable, but if you use let or const, get a block-scoped variable.

I now have to make a confession — I’ve been perpetuating a white lie through omission. ES5 variables are not just function scoped, they are also hoisted. Most of the time, variable hoisting has no noticeable effect on your code, and, many people find it very confusing, so, I’ve simply avoided mentioning it.

However, in ES6, variables declared with var will continue to be hoisted, but variables defined with let or const won’t, so it now becomes important to understand that difference.

Rather than tell you what hoisting does, I’ll show you with this very simple contrived example:

What do you expect the output to be when this little snippet is run?

Those of you not familiar with the subtitles of variable hoisting are probably expecting it to be:

I'm a global!
now I'm local!

But if you pop that code into a JavaScript console and run it, you’ll get the following instead:

now I'm local!

Huh? What’s going on here?

Variable hoisting means that JavaScript effectively re-wrote the function above to the following before executing it:

So, if you use var to declare a variable anywhere within a function, then that local variable exists within the entire function, even on the lines above your declaration!

I tend to avoid expressing strong opinions in this series, but I’ll make an exception here — I think var‘s behaviour is as nutty as squirrel poop!

Declaring Variables with let

My single favourite ES6 feature is the keyword let. That’s mainly because it makes JavaScript variables behave like variables in all the other languages I use, but also because it makes code read more intuitively — let x = 4; can very easily be mentally read as ‘let x become equal to four’.

let is just like var except that it creates variables that are block-scoped, and don’t get hoisted.

Let’s re-visit our example from above, but replace var with let:

Executing the function now gives us an error: “ReferenceError: can’t access lexical declaration `msg’ before initialization”.

Why? Because even in ES6, you can’t have your cake and eat it. Within any single scope a variable has to be either local, or from a containing scope, it can’t be both.

With block-level scopes we do have a simple solution though, just make another scope!:

Running this we finally get what we wanted:

I'm a global!
now I'm local!

One final thing to note is that re-declaring the same variable within the same scope with let will generate an error. Re-declaration isn’t something you’d ever want to do, it’s always a bug, so having ES6 throw an error when it happens is a good thing IMO.

Declaring Constants with const

Before ES6 JavaScript had no concept of a constant. Anything you declared with var could have its value changed later in the code. In other C-style languages there is generally a mechanism for marking a ‘variable’ as being un-changable, or, as being constant. For example, the value of the gravitational constant (G) doesn’t change, so if your code were to be doing gravitational calculations, it would be good to be able to store G in a variable where accidentally attempting to change it would result in an error being thrown. That would nip all sorts of subtle bugs in the bud!

That’s what the const keyword is for. It behaves just like let, except that any attempt to alter the value after declaration will result in an error.

Here’s a simple example:

Remember, variables hold primitive values and references to objects, so if you declare an object with const you can still alter the contents of the object, but you can never change the object that variable points to.

To illustrate the point, the this will generate an error:

But this won’t:

Asside — Function Hoisting

Since we’ve now mentioned the concept of hoisting, I should point out that variables aren’t the only things that get hoisted in JavaScript, function declarations do too, and that hasn’t changed in ES6.

The following works in all versions of JavaScript, including ES6:

A Challenge

In the real world, you often need to change the internals of a library of code without altering how the code behaves. Software engineers refer to this kind of code renovation as refactoring.

Over the next few instalments we’re going to refactor our cellular automaton prototypes into ES6 classes. As a first step, the challenge for this week is to refactor the prototypes so they use let and/or const as appropriate.

It’s very easy to accidentally break code while refactoring, that’s where the test suite we’ve been building up concurrently with the code comes in. Be sure to test your refactored code as you go, that way you should be able to avoid introducing new bugs.

Final Thoughts

While the change from var to let and const is significant, it’s just the beginning of our journey into the joys of ES6. In the next instalment we’ll learn about new types of loops, and about default values for function arguments.