wp-content/uploads/2016/01/PBS_Logo.png

We’ve now covered most of the core JavaScript language. We’ve learned that variables can store literal values, or references to objects. We’ve learned there are three types of literal values – numbers, booleans, and strings. We’ve learned about operators. We’ve learned about conditionals. We’ve learned about loops of various sorts, and we’ve learned about objects. We’ve learned that in JavaScript, arrays are implemented as objects with the prototype Array, and that functions are also implemented as objects.

Before we can leave the playground and head off into the world of the browser, we just have a few more loose ends to tie up, which we’ll take care of in this instalment.

Now that we know about objects, we need to re-visit the arguments object present in every JavaScript function. We need to take a detailed look at the typeof operator, and we need to look at some built-in objects and functions JavaScript provides.

We also need to look at how JavaScript handles regular expressions, and finally, we need to introduce the concept of exception handling.

Our Playground

This is the final instalment for which we’ll be using our JavaScript playground. You can download the code for the playground here, or, you can use the online version at www.bartb.ie/pbsdemos/pbs-JavaScriptPlayground/.

A Solution to the PBS 17 Challenge

In short, the challenge was to create prototypes for objects representing quotations, and a random quotation generator, and then to use these prototypes to print out three random quotations.

Again, I want to stress that there is no such thing as a definitive correct answer – there are an infinity of correct solutions to this challenge. My solution is shown below.

I want to draw your attention to a few key points in this solution.

Firstly, you can see that in the constructor for the RandomQuoter (starting on line 93), I explicitly convert the arguments object into a true array before passing it on to the .add() function. The same is also done inside the .add() function (starting at line 124).

Secondly, within the .add() function in the RandomQuoter, I need to access a property of a RandomQuoter object from within a callback. To enable this, I had to create an alias to this (at line 124), which, following convention, I named self.

Finally, I wrote the .empty() and .add() functions in the RandomQuoter prototype in such a way that they can be chained together. That is to say, you can can call .empty() and .add() one after the other by appending the function calls together. You can see this in action on line 185. This is only possible because both of those functions return a reference to this (lines 115 & 147). This very commonly used technique is referred to as function chaining.

The arguments Keyword Re-visited

In the previous instalment we learned that functions contain a variable called arguments that provides direct access to the function’s arguments. We described this object as an array, because it behaves like one, and, we had not yet learned enough about objects to be totally honest about its nature.

arguments objects sure look like arrays, allowing you to access the first argument to a function as arguments[0], the second as arguments[1], etc.. Also, arguments objects have a .length property, just like true arrays do.

However, arguments objects do not have the Array prototype, so they don’t support functions provided by that prototype, like .forEach() & .sort(), and, applying instanceof Array to an arguments object will evaluate to false, so it fails our test for whether or not something is an array.

In version 5 of ECMAScript (and older), you have to manually convert this object to a true array if you want to use it as one. You would do so using code something like:

In version 6 of ECMAScript, a better solution has been provided, but, it will not work in IE, so, it’s probably too early to start using this feature on the web. However, if you are using JavaScript in other environments, and those environments are at ECMAScript version 6 or newer, you can safely use this technique. As you can see, it is much shorter than the old manual approach:

The typeof Operator

This operator has a long history, hence, it has some rather odd behaviours, but it’s still very useful.

As we’ve already seen, the syntax for this operator is typeof value_to_test, and it will always return a string. The string will be one of the following:

  • 'number' – the value is a number literal
  • 'boolean' – the value is a boolean literal
  • 'string' – the value is a string literal
  • 'undefined' – the value is undefined
  • 'function' – the value is a reference to a function object
  • 'object' – the value is a reference to an object that is not a function object

The most obvious shortcoming is that arrays are simply returned as 'object', this is why we have to rely on the instanceof operator to determine if something is an array.

Built-in Objects & Functions

JavaScript comes with a whole bunch of useful pre-defined object prototypes and stand-alone functions built in. We couldn’t possibly go through an exhaustive list, but we will look at some common ones, grouped by topic.

String Functions

Strings are literal values, but under the hood, JavaScript converts them to objects of prototype String as needed.

The String prototype provides a property called .length, which tells you the number of characters in a string. The String prototype also provides two functions for manipulating the case of a string – .toUpperCase() and .toLowerCase(), both of which return a new string with the changes applied, rather than changing the value in the string they are called on.

As you can see in the last line of the example above, string functions and properties can be accessed directly from string literals.

Another useful string function is .charAt(), which allows you to access individual characters within a string, almost as if the string were an array of characters. The following example uses .charAt() in conjunction with a loop to reverse a string:

This above example illustrates a very important point – before using a string function on a variable, you need to be sure it really is a string, otherwise, you’ll get an error, as demonstrated by this code:

You can protect yourself from this kind of error by explicitly converting the variable to a string before applying the function. You can do that like shown in the reverse example, or, you can do it in such a way that it does not affect the value stored in the variable as show below:

Finally, the String prototype provides a function .split() which allows a string to be exploded into an array based on a given separator. The separator can be a string, or a regular expression (see below for details on regular expressions in JavaScript).

As an example, we can split a time string into an array of hour, minute, and second values by splitting it on the string :, as shown below:

Array Functions

As we already know, in JavaScript, arrays are implemented as objects with the Array prototype. This prototype brings along the useful .length property, as well as the .forEach() function, both of which we have already seen. The Array prototype brings along more functions than that though, and we’ll look at some of those now. Bear in mind that unlike with strings, some of these functions do alter the array itself, rather than returning an altered clone.

We’ll start with four related functions for adding and removing items from the ends of arrays. You can add one or more values to the end of an array with .push(), and to the front of an array with .unshift(). You can remove and return the last element of an array with .pop(), and the first element with .shift(). These four operators allow you to use arrays as stacks or queues.

There are also functions for altering the order of elements in an array – .reverse(), and .sort(). .reverse() does what you expect, and mirrors the entire array. By default, .sort() will do a lexical sort, but you have the power to sort by any rule you like thanks to the power of callbacks.

To create your own sort order, define a function that takes two arguments – if the first argument should be sorted before the second, return -1, if the second should be sorted before the first return 1, and if the two should be considered equal, return 0.

As an example, the following code shows how a default lexical sort does a terrible job of sorting numbers, and, how a callback can be used to do a numeric sort:

Finally, I also want to mention a very convenient function for joining all the elements of an array into a single string. By default, .join() will return a string representing all the values in the array, separated by a comma. You can specify your own separator by passing a string as an argument.

Mathematical Functions & Values

As well as the basic arithmetic operators we’ve already seen, JavaScript also includes a standard object called Math, which provides a number of constants and mathematical functions. This is not an exhaustive list, but here are some commonly used values and functions.

Firstly, the object has values for common mathematical constants including, Math.PI for pi, Math.LN10 for the natural log of 10, Math.LN2 for the natural log of 2, and Math.E for Euler’s constant.

The Math object also provides functions for applying common mathematical operators that are not covered by the builtin operators. For example, the trigonometric functions – Math.cos(), Math.sin() & Math.tan().

There are also many useful functions for rounding numbers, including Math.floor() to round down, Math.ceil() to round up, and Math.round() to round to the nearest integer. There is also Math.abs() to get the absolute value of a number (remove the minus if present).

Also worth mentioning is Math.sqrt(), for getting the square roots of numbers.

Something that’s worth focusing on in more detail is JavaScript’s random number generator, which is also provided by the Maths object. Math.random() will return a random floating point number between zero and one. The number returned can be exactly, zero, but cannot be exactly one. By combining this function with some simple arithmetic and the rounding functions mentioned above, we can generate random numbers in any range we need.

E.g. we can generate a random integer between zero and 99 (inclusive) with the following simple code:

Or, between 1 an 100 inclusive with the following code:

Regular Expressions

I’m going assume you know what regular expressions are. If not, please see instalment 17 and instalment 18 of the Taming the Terminal series for an explanation. Like egrep, JavaScript uses Perl-style regular expressions.

In JavaScript, regular expressions are represented as objects with the prototype RegExp. Like strings, arrays, and objects, you don’t have to use the new keyword to create regular expression objects, you can use the following special syntax instead:

For example, you can create a regular expression that matches positive integers like so:

The RegExp prototype provides a number of useful functions that we should take a look at.

First, you can use the .test() function to test if a string matches a regular expression:

Secondly, you can use the .exec() function to do more detailed matching, including accessing sub-matches, and iterating over multiple matches within the same string.

Let’s start with the simplest example – using .exec() to access sub matches. Reminder – you create sub-matches within a regular expression using parentheses. If the test string does not match the regular expression at all, .exec() returns null, and if the string does match, a results object is returned. If a results object is returned, the entire matched text will be in results[0], the first sub-match will be in results[1], the second in results[2], and so on.

Notice that it is the order of the opening parentheses that defines the order of the sub-matches – hence the decimal part of the amount being third.

If our regular expression has the g flag (for a global match), .exec() will remember where it left off, and next time you call it, it will give you the next result, so, you can loop through all the matches like so:

When you think about it, regular expressions are very closely related to strings. To make code simpler, JavaScript includes a number of regular expression related functions in the String prototype. This allows you to reverse the logic, instead of calling a function on an RE that you pass a string, you can call a function on a string that you pass an RE. There are two such functions in the String prototype.

You can test if a string matches a given regular expression with the .match() function. The function takes an RE as an argument, and returns null if the string does not match, and an array of matches and sub-matches if it does.

Because null evaluates to false, you can do simple testing like so:

If your RE has the g flag, you can also use .match() to find all matches like so:

Finally, the String prototype also contains a function .replace(), which searches a string for a given RE, and then replaces the matching text in the string with a given substitution. The first argument passed to .replace() is the regular expression, the second, the substitution. The function does not alter the string it’s called on, instead, it returns a new string with the replacements in place.

The specified replacement can take one of two forms – a string, or, a callback.

If you pass a string as the replacement, you can use $1, $2 etc. to reference any sub-matches. If you want your replacement to contain an actual $ symbol, you need to write it as $$. You can use $& to include the entire matched string.

The following replacement will find all currency values of the form €1.23, and replace them with the form 1.23EUR.

Note that if you leave off the g flag, only the first match will get replaced.

Now lets look at the more complex option for the replacement, a callback. The callback will be run once for every match (if the RE does not have a g flag only one match will be found). It will be called with the full matching string as the first argument, followed by each sub-match as subsequent arguments. The callback should return the replacement text as a string.

We can use this technique to do mathematical calculations in our replacement, e.g., the following will replace all Fahrenheit temperatures with their celsius equivalents:

Error Handling with Exceptions

When writing re-usable code, like functions, it is good practice to test assumptions made about the inputs/arguments before using them in the code. This approach tends to lead to robust code, and for that reason, the examples in this series use that approach. What I want to look at now is different approaches for what to do when you detect an error. So far in the series we have been returning some kind of special value to indicate failure. Depending on the situation, perhaps NaN, or zero, or false.

This approach works, but, it has a distinct drawback. When your function is used, the only way to get value out of all that error checking is to test the output for the special value that indicates failure.

There is a better way. When something goes wrong, we should not return a special value, instead, we should use JavaScript’s in-built mechanism for raising the alarm that something has gone wrong. Specifically, we should throw an exception. This mechanism is known as exception handling. JavaScript’s implementation of exception handling is very heavily influenced by Java, so Java programmers should feel right at home with it.

Exception handling is very much a game of two halves, and, one of those halves is optional.

When something goes wrong, your code should use the JavaScript keyword throw to throw an Error object. For example, we could re-write our factorial function from previous instalments to be exception-aware like so:

As you can see, this function correctly calculates the factorial, and, when given valid input, behaves normally.

However, when we give it bogus input (the string boogers in this case), it triggers an error, and, execution of the code stops (the last line never happens).

In this case, we did not make any kind of effort to catch the error that was thrown, so, the error was handed up to the playground, and the playground dealt with it as best it could – by putting up a red message with a warning triangle, and ceasing execution. As far as the playground is concerned, this error is no different to a syntax error, like forgetting to close a bracket. An error is an error is an error.

The second part to exception handling is catching what you throw. Rather than letting the playground catch the errors we throw, we can catch them in our own code, and then deal with them in a sensible way. The syntax for this is a so-called try-catch block. The syntax takes the following form:

The error message within an Error object can be accessed using its .message property.

We can now use the try and catch keywords to safely call our factorial() function with the values entered in the playground inputs as show below (the function itself has not been changed):

Try running this code with no inputs, all valid inputs, and then a mix of valid and invalid inputs. You’ll see that the code behaves nicely in all those situations.

You’ll also notice that by catching the errors thrown within factorial(), they never make it to the playground, so no red error messages, and an error while calculating the factorial on one input does not stop the remainder of the code from running.

PBS JavaScript Cheat-Sheet

The JavaScript cheat-sheet has been updated to include the what we learned in this instalment.

A Challenge

Create a prototype called IP that will represent an IP address. Internally, the IP address should be stored as an array of four integers. The constructor should default to the IP 0.0.0.0, but should optionally accept an IP address as an argument, either as a string, or, as an array of integers.

Add a function to the IP prototype named .parse() – this function should take a string or an array as an argument, and, if the passed value is a valid IP, set the internally stored IP to the given IP address. The function should throw an error if it receives invalid arguments

Add another function to the IP prototype named .toArray(). This function requires no arguments, and should return the IP address as a fresh array (not a reference to the internal array, i.e. a clone).

Finally, add a third function to the IP prototype named .toString(). This function should return the IP as a string in the normal dotted format.

Reminder – an IP address consists of four positive integer numbers between 0 and 255 inclusive, separated by period (full stop) symbols.

Next, create a prototype called Subnet. The constructor should require two arguments – the network address for the subnet as an IP object, and the class for the subnet as a string – valid classes are A, B, and C. If the constructor receives invalid arguments, it should throw an error.

Add a function named .toString() to the Subnet prototype which will return a string consisting of the IP address as a string, followed by a forward slash, and then 255.0.0.0 for class A subnets, 255.255.0.0 for class B subnets, and 255.255.255.0 for class C subnets.

Finally, add a function named .test() to the Subnet prototype for testing if a given IP is within the represented subnet. The function should require one argument, an IP object. If the subnet is a class A, check that the first part of the given IP matches the first part of the internal IP of the subnet. If class B, check the first two parts, and if class C, the first three. The function should return true if the IP is within the subnet, and false otherwise, including on invalid arguments.

Finally, test your prototypes by creating a subnet from playground inputs 1 and 2, and testing it against an IP address from playground input 3.

Conclusions

We’ve now built up a very robust understanding of the core JavaScript language. That knowledge is not application-specific, but can be used in any of the many contexts JavaScript is used in today. In this series, we’re going to use this knowledge to learn how to do client-side scripting on web pages. In other words, we’ll be using JavaScript to bring web pages to life.