Contents


The busy JavaScript developer's guide to ECMAScript 6, Part 2

Functional enhancements

Using arrows, generators, and other functional elements in your JavaScript programs

Comments

Content series:

This content is part # of 4 in the series: The busy JavaScript developer's guide to ECMAScript 6, Part 2

Stay tuned for additional content in this series.

This content is part of the series:The busy JavaScript developer's guide to ECMAScript 6, Part 2

Stay tuned for additional content in this series.

Interactive code: When you see Run at the top of a code sample, you can run the code, check the results, make changes, and run it again.

Welcome back to this introduction ECMAScript 6 for JavaScript developers. In Part 1, you learned about six language updates that address longstanding issues in JavaScript, or just make coding certain features easier. Among these was the new destructuring assignment operation, which is used in variable declarations to destruct an array or object to its constituent parts. If you haven't already read Part 1, you should do that now; I'll presume you have that background for some of the discussion here.

Part 2 is dedicated to language updates that will change how you work with functions in JavaScript. Among other things we'll look at function definitions and call syntax, and you'll learn more about destructuring assignment, this time in function definitions. I'll also introduce the new arrow function syntax and generator functions, the latter of which puts an interesting spin on the classic iterator and ye oldefor loop.

Destructuring in function declarations

JavaScript's new destructuring assignment gets its name from the idea that an array or object can be "destructured" and extracted into its component parts. In Part 1 you learned how to use destructuring in local variables. It also can be useful in function parameter declarations.

If a function is expecting an object, you can use destructuring to extract the relevant parts of that object even before the function begins. Do this by adding destructuring syntax to the function's arguments, as shown in this listing.

Show result

The displayDetails function only cares about the firstName and age fields of the object being passed in. Adding a destructuring assignment to the object syntax effectively extracts those values as part of the function call. The call syntax itself remains unchanged, making it easier to refactor legacy code to use the new syntax.

You can also use destructuring array syntax in functions, but it's less impressive than some of the other features you're about to see.

Function parameters

ECMAScript has made a few syntactic changes to function parameters. Specifically, it's introduced default parameter values, rest parameters, and the spread operator for function calls. As I've mentioned before, most of these are syntactic sugar over conventions that ECMAScript developers have been using for years. Now that they're full-blown language features, you can accomplish the same work using fewer lines of code.

We'll start with default parameters, probably the easiest of the three to understand.

Default parameters

In addition to allowing for destructuring syntax, ECMAScript 6 now offers a default parameter value syntax similar to what's found in several C-family languages. Even if you've never seen default parameters before, the syntax is fairly obvious and intuitive:

Show result

In essence: if a parameter is specified at the call site, then the parameter takes the value passed; if no value is specified, then the default value is assigned.

As with some of the updates introduced in Part 1, the new default parameter is essentially syntactic sugar. Here's how you might have coded it in prior versions of ECMAScript:

Show result

The new syntax is simply shorter and more expressive, and standardizes what many programmers have been doing for years.

Rest parameters

One of the more common idioms in ECMAScript libraries is to define functions or methods that take one or more fixed parameters, followed by a collection of optional parameters that refine or modify the call in a user-defined way. Historically, you might have done this by accessing the built-in arguments parameter that is silently constructed and passed to every function call:

Show result

Using the new rest parameters syntax, you can capture the optional arguments into a local array variable. You use them the same as above, but without modification:

Show result

Notice that the rest parameter (args in the first listing) doesn't need to be tested for existence; the language guarantees that it will exist as a 0-length array, even if no additional parameters are passed.

Spread operator

The spread operator is in some ways the conceptual opposite of the rest parameter. Whereas the rest parameter collects a number of optional values passed in a given call, the spread operator takes an array of values and "spreads" them out, basically destructuring them to be used as individual parameters to the function being invoked.

Spread's simplest use case is to concatenate individual elements into an array:

Show result

Without the spread operator syntax, you would need to extract and append each individual element of the first array to the second array, before adding in the remaining elements.

You can also use the spread operator in function calls; in fact, that's where you'll likely use it the most:

Show result

Note that unlike the rest parameter, the spread operator is used at the point of call, not in the function definition.

Function syntax and semantics

On top of the changes to parameters, ECMAScript 6 has made major changes with respect to function syntax and semantics. We'll tour the most significant updates in this section. Just remember that the original syntax remains viable in JavaScript programs. You can ease in to using this new syntax if it doesn't feel comfortable or intuitive at first.

Arrow function

As newer functional languages like Scala and F# have gained mainstream acceptance, older standbys have started adopting some of their shinier features. One such feature is the arrow function syntax, a symbolic shorthand used to create function literals. Starting with ECMAScript 6, you can use the so-called fat arrow (as opposed to its skinny cousin) to create function literals, like so:

Show result

If you've tried your hand at functional programming in C#, Java™ 8, Scala, or F# you're likely familiar with this syntax. Even if you're not familiar with it, the arrow is pretty easy to understand: the parentheses before the arrow capture the parameters to the function body, and the arrow itself sets off the start of the function body. If the body consists of a single statement or expression, there's no need for curly braces. If the body contains multiple statements or expressions, you can denote that by putting braces immediately after the arrow:

Show result

If there is only one parameter, you can choose to leave out the parentheses entirely. The syntax
names.forEach(n => console.log(n));
works just fine. (Personally, I use parentheses for even a single parameter, but that's an aesthetic preference about which reasonable people can reasonably disagree.)

Also note that if the body of the arrow function is a single expression yielding a value, no explicit return is required. Instead, that single expression is implicitly returned to the arrow function's caller. If, however, the body is more than one statement or expression, the curly brackets are mandatory, and any returned value must be sent back to the caller via the usual "return" syntax.

A new definition for 'this'

Long before pen was ever put to page for ECMAScript 6, programmers have struggled to figure out what ECMAScript's this parameter points to. Ostensibly, as with other C-family languages, this is the parameter that references the object on which a method is being invoked, as shown here:

Show result

The above parameter clearly references the instance bob, and dutifully prints out the name and values of firstName, lastName, and (since it too is a member of the object) the displayMe method.

Things get a little weirder when this is referenced from a function that exists at the global scope:

Show result

For the uninitiated, ECMAScript defines the global scope as an object, so when used from a function in the global scope, this references the global scope object. In the case above it would dutifully print out each member of the global scope, including top-level global variables, functions, and objects (such as "console" in the above example).

Because of this, we can also reuse the function in two separate contexts, knowing that each time it will do more or less what we expect:

Show result

The syntax is a bit odd, perhaps, but not a problem as long as you understand the rules. It's not until you try using ECMAScript constructor functions as object types that things start to go really sideways:

Show result

You might expect the value of p.age to increase by 1 after a tenth of a second. But because the this in the growUp function literal refers to the global object instead of p, the value of p.age never changes from 0. (Normally you would have your Person object age forever by invoking the growUp() function with setInterval. However, the developerWorks sandbox doesn't support code that runs indefinitely, so this example uses setTimeout instead.)

Lexical 'this' binding

To resolve the definition issues associated with this, arrow functions have what's called lexical this binding. This means that the arrow function uses the this value at the time the function is defined, not the time it's executed.

Perhaps the easiest way to understand the difference is with an old Node.js standby, the EventEmitter. Recall that the EventEmitter (obtained from the events module) is a simple pub-sub style messaging system: You can register callbacks on the emitter on a particular event name, and when that event is "emitted," the callback(s) are fired in the order in which they were registered.

If you register a legacy function with the EventEmitter, the this captured will be the one determined at runtime. But if you register an arrow function with the EventEmitter, this will be bound at the time the arrow function is defined:

Show result

When the function events are fired, this is bound to the EventEmitter itself, whereas the arrow events are bound to effectively nothing (they each print an empty object).

Generator function

Generators are functions that are designed to produce a stream of values for consumption by other parties. Generators are used in a number of functional languages, where you might know them as streams or sequences. Now they've come to ECMAScript.

Understanding how generators work in practice requires a bit of explanation. To start, we define a simple collection of names. Now say that we want a function to return each of the names, one at a time per function call, until none are left:

Show result

At first, the above function-returning-a-function sleight-of-hand might seem strange. It's necessary because the getName function needs to track its state across multiple function calls. In a language like C, we could store state in a static variable inside the getName function, but like its cousins Java and C#, ECMAScript doesn't support static variables in a function. In this case we use a closure, so that the function literal holds on to the "current" variable after it returns, and uses that for its state.

The key thing to understand is that rather than handing back a finite sequence of values all at once (a la returning the array), this function hands each element back one at a time, until no more elements remain.

But what if you never ran out of elements to return?

Infinite streams in functional programming

It might seem like the previous code example is not much improvement over using an iterator across the names array. After all, that's what iterators do: provide individual element access across the contents of a collection. The important change comes when the original array is no longer visible, and isn't even an array anymore:

Show result

Technically, what you see is still an iterator, but its implementation looks wildly different from the iterators from patterns books; there's no collection here, just a set of hard-coded values.

In essence, it's an iterator without an associated collection, which highlights something important: that the source of the values being produced by our function is now deeply encapsulated away from the caller. This in turn creates an even more interesting idea: that the caller could be unaware that there is no collection to begin with, and that the values being produced are unending. This is what some languages call an infinite stream.

The Fibonacci sequence (the "Hello World" equivalent for every functional language on the planet) is one such infinite stream:

Show result

An infinite stream is one that will never run out of values to return. In this case, there is no logical end to the Fibonacci series.

While it might seem strange at first, the infinite stream concept is at the heart of some other interesting ECMAScript-based technology, such as reactive programming. Consider what happens if we think about user events (like mouse moves, button clicks, and key-presses) as infinite streams, which are then consumed by functions that pull each event off the stream and handle it.

The amount of code required to build an infinite stream is cumbersome, so ECMAScript 6 defines a new syntax (and a new keyword) to make things more succinct. You can see it here:

Show result

Once again, the function will print each name in order. When it runs out of names it will print "undefined" ad infinitum. Syntactically, the yield keyword looks like a return, but in fact, it's a "return but remember where I was inside this function, so that the next time it's called, we pick up execution where we left off." That's obviously a bit more complicated than the traditional return.

Using the generator is a bit different from the first example: we've captured the return of the getName function, then used that object like an iterator. This is a deliberate design decision in ECMAScript 6. Technically, a generator function returns a Generator object, which is used to obtain the individual values from the generator function. The new syntax is designed to emulate iterators as closely as possible.

Speaking of iterators, there's one last syntax change you need to know about.

The for-of keyword

The classic for loop gets a new look in ECMAScript 6, due to the addition of a secondary keyword: of. In many ways, the new syntax is not much different from for-in, but it supports things like generator functions.

Going back to the Fibonacci sequence, here's what happens if you add a for-of keyword to the function:

Show result

There's a subtle difference between for-of and for-in, but for the most part you can use for-of as a drop-in replacement for the older syntax. It just adds the ability to use generators implicitly—like we did with getName() in the infinite streams example.

Conclusion

By now you've noticed that ECMAScript 6 definitely isn't a simple errata release. Many of the features I've introduced here stem from functional programming concepts, but don't let that fool you: ECMAScript 6 is far from a functional language. Adopting certain functional features can make writing ECMAScript code easier, but you don't need to know about monads, monoids, and category theory to do it. For the most part, the prevailing attitude seems to be: If it works for you, use it; if not, there are lots of other options.

So if you've never done any functional programming, don't stress—ECMAScript 6 invites you to dip your toes in the water, but you're definitely not going to be tossed into the deep end of the pool.

In any case, the next article in this series returns us to dry ground, with a guide to the new class-based syntax and object enhancements in ECMAScript 6.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=1038069
ArticleTitle=The busy JavaScript developer's guide to ECMAScript 6, Part 2: Functional enhancements
publish-date=05032017