Chapter 3. Features Explained

ECMAScript 6 contains a large bundle of new features for programmers to explore, bringing different pieces to different projects.

Arrow Functions

When JavaScript programmers talk about what this means in JavaScript, you may feel like you’re watching “Who’s on First?” For those who are new to JavaScript, understanding what this is can often prove difficult.

What better way to provide clarity than to add yet another meaning for this? Arrow functions are a new syntax that allow developers to manage their scope differently than before, providing yet another value for this.

While that may sound confusing, arrow functions will help make JavaScript code more readable. When using arrow functions, your code reads the same way that it will execute. The same cannot be said for all usages of this. Such functionality will help make JavaScript code more readable and predictable for developers, which translates into easier maintainability.

In addition to helping developers understand what this is, arrow functions have some syntactic sugar that allows you to opt-out of using the function and return syntax in your functions.

Let, Const, and Block Functions

Prior to the ES6 release, each time you declared a new variable, you used the keyword var. There were no alternate keywords to define a variable. Starting with the ES6 release, you will now have two additional constructs for defining new variables: const and let.

Using const makes your variables a constant value. Variables defined using the keyword const will never be changeable. Other languages call these final variables, as their value cannot be changed once it is set.

Let, on the other hand, is more like var, in the sense that you can change the value repeatedly. Where let and var differ is in relation to how they scope themselves. To the chagrin of many JavaScript developers, using the keyword var to define your variables can leave you with code that looks one way but acts differently when it comes time to be executed. Think of the maintainability of your code. Using let instead of var produces clearer code, which is the linchpin of maintainability. Let forces the code to act the way it is written. That behavior makes life easier for your developers.

Destructuring

As you pass data around inside your apps, you will invariably need to pull pieces of the data apart to examine them individually. The task of pulling data apart is also referred to as destructuring the data, because you are taking the data’s structure apart. Prior to ES6, programmers were required to be fairly verbose while destructuring their data. ES6 Destructuring allows you to perform the same task of taking your data apart with a lot less code.

Default Values

Toward the top of many JavaScript functions there is code that verifies that all incoming parameters have a value and are not left undefined. Unwanted undefined values can create hard-to-find bugs in code. ES6 Default Values allow you to elegantly verify and provide default values for each of your parameters. It has always been possible to catch these undefined parameters and trap them before they make a mess; however, the new Default Values syntax simply makes it much easier. Many other modern languages have this feature.

Modules

Prior to ES6, JavaScript had two main competing module systems: AMD and CommonJS. Neither is native to the browser: they are monkey-patched into the browser at run time. Both of these module systems have different strengths. When it came time for the TC39 to decide between the two, the committee decided to come up with yet another approach for modules. The new approach is elegant and covers an even wider spread of functionality then either of the predecessors.

Modules, in general, solve several problems for developers. First, they allow the developer to separate code into smaller pieces, called modules. Second, they make it easy for developers to load (inject) those modules into other sections of code. Having modules injected like this helps keep project code uncoupled from the module (read: improved testability). And third, modules can load scripts asynchronously. This means that apps can begin loading faster, as they don’t require all scripts to be loaded prior to executing code.

Under the current proposal, modules will provide features from both AMD and CommonJS. In addition, ES6 modules have additional pieces that don’t exist in either of the others.

Classes

One of the easiest ways to reuse code is by allowing one piece of code to inherit the functionality from another piece. This way, both pieces of code have the same functionality, but the code only gets written once. By using an inheritance chain known as prototypes, JavaScript has always been able to share code this way.

While prototype chaining works, most other object-oriented programming languages use a variation of class-based inheritance to share code from one piece of code to another. Starting in ES6, you will be able to define and inherit functionality by using classes as well as prototypes. The syntax to share code using classes is much cleaner than its equivalent in prototypical code sharing.

This feature polarizes JavaScript developers. You won’t find many developers who are on the fence with regard to classes in JavaScript. They will either like it or dislike it.

As I see it, classes have two main advantages. First, classes add some syntactic sugar to inheritance in JavaScript. This means that inheritance in ES6 will be more straightforward, and the code will be easier to follow. Second, once classes have completely replaced traditional prototype-inheritance, regular functions will have a smaller footprint in memory. Still, I am hesitant to embrace the addition of classes to the ECMAScript specification. I fear the cleverness of the masses. I don’t fear the feature: I fear how people will use classes. If you ever have JavaScript class named com.myapp.mymodule.Factory.Provider.AbstractProxyServiceImpl, you are simply doing it wrong.

On a positive note, classes should allow IDEs to be more intelligent as they inspect code. This type of real-time feedback may allow developers to catch bugs earlier than ever before.

Rest Parameters

The term “rest” frequently refers to REST, a common model for writing web services. In the context of the ES6 release, “rest” has nothing to do with a web service.

Many other modern languages allow you to make a method that takes a non-predetermined number of parameters. Consider a function called add. It may need to add 2 numbers together; it may need to add 100 numbers together. You wouldn’t want to write 99 separate functions called add so that you can simply add a dynamic amount of numbers together, would you? ES6 Rest Parameters now give JavaScript the ability to have functions that have no predetermined number of parameters.

Previously in JavaScript, if you wanted to pass around a dynamic amount of numbers, you had to put them inside a container, like an array. Rest Parameters allow you to just pass the numbers, without jumping through the hoop of wrapping them in a container.

Spreading

Arrays are just linear collections of objects. They could be a collection of numbers, words, or even other arrays, for example. How can you get things out of the array once they are there? Looking backward, you always had to reference each of the items one by one. This always worked; however, it tends to be a bit verbose, not to mention that the code can become cryptic. ES6 Spreading allows you to easily spread out the array, without all the mess.

Proper Tail Calls

Proper tail calls leverage a low-level enhancement inside the JavaScript engines. In spite of the many things that JavaScript is good at, it has always been notably horrific at recursion. A recursive method is one that will call itself over and over again. These methods may only need to do this a few times or they may need to recurse tens of thousands of times. Each time the method calls itself, it consumes more memory. There is no limit to the amount of memory that recursion may use. Within milliseconds, it is capable of crashing your entire website due to memory consumption.

ES6 proper tail calls allow JavaScript to run a properly written recursive function that can call itself tens of thousands of times without using additional memory for each call. Fibonacci sequence, here we come!

Sets

JavaScript has has two very powerful containers: arrays and objects. Arrays are lightweight containers. You can treat them like a queue or a list, popping an object off the end, or shifting an object off the front. However, there were some things that an array couldn’t easily do.

Prior to ES6, if you wanted to have an array without any duplicates, you had to write your own code to prevent duplicates from being added to the array. This duplicate-preventing functionality now comes built in with Sets. Sets are very much like arrays in JavaScript. However, if you try to add the same value twice to a set, the set will simply ignore the second attempt to add that value. With Sets there is now an easy way to have collections of unique values.

Maps

In other languages, we refer to maps as hashmaps or dictionaries. A hashmap maps a key with a value. An example would be mapping the key “name” with the value “Freddie Mercury” and the key “band” with the value “Queen.”

JavaScript has had these hashmaps for a long time. In fact, JSON is an entire data structure based on keys that are mapped to values.

Maps adds functionality to JavaScript’s JSON and Object Literal syntax. Historically, you could only use strings and numbers as keys in object literals. With the new Map object, however, you can use any object as the key. We aren’t restricted to strings and numbers. You could have a key that is a function or an HTML element. Maps are more dictionary-like than anything JavaScript has ever had.

Weak Maps

Weak maps are exactly like maps, with a few exceptions. The primary difference is: weak maps can make cleanup easy.

Suppose you have a map and add a key that represents some HTML element from your page. If that HTML element is ever removed from your DOM, having a reference to that element in your map prevent the browser from completely removing the HTML element from memory. Because the map still points to the element, the garbage collector will leave it alone until the map is destroyed.

Unlike a map, weak maps will let the garbage collector remove the element from memory. If the only reference to the HTML element is the key in the weak map, the weak map will release its reference as well. Once all references have been dropped, you can then say goodbye to the HTML element forever.

egal

Egal is French for equal. In ES6, egal is yet another way to test the equality of two objects.

When you compare values in JavaScript, egal gives you an optional way of checking for equality. In addition to x === y, you may now use the is syntax. Instead of dropping three equal signs to ask if two references point to the same object, you may now use the following syntax: x is y or x===y. Functionally, these two comparators are the same.

While no decisions have been finalized, the TC39 are also considering the addition of x isnt y to the language as well. This would make inequality testing easier.

Generators

Generators are functions that can be paused. By adding the keyword yield inside our generator functions, the system will pause the execution of code, return the value to the right of the keyword yield, and wait until we tell it to continue. (Generators have been in Firefox for quite a while now.)

Generators have many practical uses. One would be generating unique IDs. Each time you need a new ID you could call generator.next(). The generator would return the next ID and then pause again. You could write your own for loops with generators, along with many other features. I predict that generators will help library and framework authors to produce more efficient code.

Iterators

In conjunction with generators, iterators offer enhanced support for looping. If you have an object that is iterable, you may now use a new for loop to iterate through that object’s properties. The new for…in loops make it easier to go through an object’s values. Prior to iterators, you needed to reference each value by first referencing the key, and then using it to retrieve its values. For…in loops give us direct access to the object’s values.

Direct Proxies (and Supporting Features)

Direct proxies are not an ES6 feature that developers will use daily. Direct proxies allow developers to intercept method calls on an object and have a separate object perform those instructions instead. While this sounds complicated and entirely convoluted, they will provide increased functionality for library builders. Direct proxies help developers abstract functionality out of individual objects and into more powerful APIs.

To drive the point home, one could use a proxy when saving an object in JavaScript. When you tell the object to save itself, you may have a proxy that intercepts and carries out the save instruction. As of today, the proxy might save the object to your server. At a later date you may need to implement a new proxy that saves the object to your browser’s localStorage. Simply switching the proxy can change where your objects save. This can be done without ever modifying the object code.

Along with the ability to proxy method calls, several other changes were needed in order to completely enable proxies to work, including prototype climbing refactoring, a new reflect API, virtual objects API, and some extensions to the object API.

Quasis

ES6 Quasis fill multiple roles. One role is templating; another is string interpolation. In the browser, JavaScript is often used to glue together HTML, CSS, JSON, and XML. While there are many client-side templating libraries out there, they will all enjoy what ES6 Quasis have to offer.

Quasis will perform much faster than any templating library could ever hope to. Additionally, they will come packed with all sorts of data-scrubbing goodies to help developers prevent security issues like cross-site scripting, SQL injection, and more. And finally, Quasis will allow developers to use multiline strings. Any developer that denies lusting after multiline strings is lying.

While the name “Quasis” is unfortunate, I am confident that they will quickly become one of the most widely used pieces of the ES6 release.

Binary Data

The binary data enhancements in ES6 aim to provide some performance gains when working with binary data in JavaScript. APIs such as the Canvas API or FileReader API return binary data. By improving performance behind the scenes, these APIs will perform much faster at run time than they ever have before.

API Improvements

The Number, Regex, String, and Math global objects each have a handful of improvements in the newest version of JavaScript. None of the enhancements are major. Most of the methods that are new are utility methods that many people have built on their own.

Unicode

Beginning in ES6, JavaScript will begin supporting UTF-16. These changes will add better support for a wider range of less frequently encountered characters.