Analysis / Technology / Top Stories / Tutorials /

The Fat Arrow Points This Way: Easy ES6 Goodies for Busy JavaScript Developers

14 Nov 2017 3:00am, by

In the beginning, there was LiveScript, begat by Brendan Eich. Tasked by the Netscape skybeards to create a scripting language to grant unto designers and programmers of the early World Wide Web the ability to assemble unto the browser components, yea such as images and plugins, whose code could be written directly unto the page markup. Eich labored ten days and ten nights in May 1995 to bring forth from the darkness a computer language, Mocha/LiveScript, that was quickly and confusingly renamed JavaScript.

And lo it was good.

Many hands were thence laid upon JavaScript to bear it unto current days.  In 1997, ECMAScript codified and standardized the language, which leadeth us unto 1999 in the age of Internet Explorer 5, and the creation of ECMAScript 3, henceforth known as ES3. Dark forces worked to deny progress thence, and ES4 was thwarted, but lo the powers of AJAX and scrappy open source developers brought forth into the light of 2009 the JavaScript version most of us learneth by: ES5.

It was an era of great prosperity in the Internets, and the peace of standard JSON lay upon the land. But time moveth forward, as doth technology, and ES6, ECMAScript2015, is now upon the people. ES6 haveth mostly syntactic sugar, because the ECMA council — which at last includeth ladies — argued long and fruitlessly over including anything more groundbreaking in the standard, such as Asynch functions. Until they see fit to render unto we the web developers ES7, however, it behooveth us to linger upon the improvements of ES6 and use them wisely.

Tl:dr that biblical nonsense — what’s worth using in ES6?

ES6, first released in 2015, was a major upgrade to JavaScript. Some of the most useful and easiest-to-pick-up parts let us produce code that is sleeker and cleaner, and often more readable. So here, in no particular order, are a few sweet little tricks to pick up and start using today, in case you are not yet one of the cool kids who have already followed the fat arrow to ECMAScript 2015 and beyond:

The Beauty of Backticks

ES6 introduces template literals, a new way to output variables in a string. Where previously we had

var id = 'Your name is ' + firstName + ' ' + lastName + '.'
var url = 'http://localhost:8080/api/messages/' + id

ES6 now gives us the ability us enclose a new syntax inside of two backtick characters:  `${varName here}` like so:

var id = `Your name is ${firstName} ${lastName}.`
var url = `http://localhost:8080/api/messages/${id}`

An additional tasty tidbit on this particular ES6 saucer is the ability to easily format multiline strings without the need for newline breaks and escaped special characters:

var ironButterfly = 'Innagadadavida, honey\n\don\’\t you know  that I\’\m lovin you?’;

becomes…

var ironButterfly = `Innagadadavida, honey,
Don’t you know that I’m lovin you?`

Follow the Fat Arrow

This is the ES 6 feature that, for me, is both the happiest and maybe most annoying.

First, my personal happy dance with this is because my main enjoyment of CoffeeScript was its arrow syntax, which struck me as making all kinds of sense. Fat arrows are a beautiful thing not just for economy of code, but because they also come with their own lexical this binding.

In ES5, this can mutate whenever you create a closure, which can lead to unforeseen code behavior and much cursing. ES6 brings us the fat arrow function syntax — => — where “this” always retains function context, i.e., “this” will always be bound to the scope of the function or method which contains it. SO much typing saved! Not to mention stress: No more need for “that=this” or .bind(this) or other such tedious yet necessary statements!  We go from:

let chicken = {  
    name: 'Pidgey',  
    jobs: ['scratch for worms', 'lay eggs', 'roost'],  
    showJobs: function() {  
       let _this= this;  
       this.jobs.forEach(function(job) {  
       console.log(`${_this.name} wants to ${job}`);  
       });
    }
};

To the more economical — and lexically stable —

let chicken = {
     name: 'Pidgey',
     jobs:['scratch for worms', 'lay eggs', 'roost'],
     showJobs() {
        this.jobs.forEach((job) => {
        console.log(`${this.name} wants to ${job}`);
       });
    }
};
chicken.showJobs();
//Pidgey wants to scratch for worms
//Pidgey wants to lay eggs
//Pidgey wants to roost

The maddening part of ES6 arrow functions is that the ECMA brains did not see fit to also give us the skinny arrow. Which essentially replaces garden variety “function” syntax, only without setting a lexical this. Too much candy at one time is bad for us, maybe? I don’t know. Perhaps ES7’s quiver will hold the skinny arrow…

A couple fat arrow things to keep in mind:

  • You can mix and match — i.e., nest the  => inside traditional function declarations, with no conflict
  • As a handy new built-in for single statements: Arrow functions used as a single line expression implicitly return the result of that statement without the need to include a return statement. (More than one line, you’re still going to need to explicitly state “return”).
  • Finally, parentheses () for single parameters are optional in arrow functions. You still need them for multiple params, though.

Let It Be

You’ve likely already run into let and const. Like var, these are used for variable assignment, but let and const both come bearing functional semantic significance.

In ES5 and before, declarations using var were subject to variable hoisting, moved to the top of the function (or global scope, if declared outside of a function) regardless of where they were declared in a code. (Making possible that favorite zen koan of the job interview JavaScript code challenge: is it possible to call a function whose variables have not yet been declared?).

Const and let, however, add the concept of block scope to declaring variables.  Just like var,  const and let each can define a variable that can be called upon inside and outside of functions — good ol’ global and local scoping. With these two new variable declaration keywords, however, ES6 adds a new and even more specific level of scope: block scoping.

The let keyword declares a block scope local variable, optionally initializing it to a value. Variables declared by let have as their scope the block in which they are defined, as well as in any contained sub-blocks — defined by curly braces. In this way, let works very much like var. The main difference is that the scope of a var variable is kind of promiscuous in that it can fall literally anywhere within the entire enclosing function:

function varProblem(es6) {
var oldschool = 'Non-block variable'
if (es6) {
var oldschool = 'Now I am block scoped!'
        }
 { // this is a NEW block - dig the curly braces!
     var oldschool='REALLY block scoped!'
     {//another NEW block:
      var oldschool = 'REALLY REALLY REALLY!'
      }
  }  
return oldschool
}

console.log(varProblem())   // “REALLY REALLY REALLY”

A simple change has radical results:

function letsTryLet(es6) {
var oldschool = 'Non-block variable'
if (es6) {
let oldschool = 'Now I am block scoped!'
        }
 { // a new block
    let oldschool='REALLY block scoped!'
    {
      let oldschool = 'REALLY REALLY REALLY!'
      }
  }  
return oldschool
}

console.log(letsTryLet())  // “Non-block variable”

 

See the difference? Even still initializing ‘oldschool’ with var (which is not best practice — done here only for purposes of illustration), using let for subsequent variable declarations contains them to their respective blocks. Since within those blocks we didn’t actually tell JavaScript to do anything, to return any new value, the assignment just sits there untouched, like a vegemite sandwich in a Tupperware box.

It is important to note the introduction of the concept of the Temporal Dead Zone. Which sounds like something from a Doctor Who episode but sadly has nothing to do with time shifting. But it’s important to our new friend let. You see, inside any given block, the lines between the start of that block up until the point in which a let variable is initialized is known as the Temporal Dead Zone. In that zone, attempting to reference that let variable (before you declare it) returns a ReferenceError. In the old var world, we didn’t get the error because of ES support for hoisting. So important takeaway: variables declared with let don’t get hoisted. So their placement within a code block has functional significance.

Const-ant pain

The const statement is block-scoped, just like let. Unlike let, however, const declarations cannot be re-declared or changed through subsequent re-assignment. Const quite frankly is a pain in the ass that way. Honestly, I’m still wrestling with it. But the introduction of const made many coders — you know who you are, the people who secretly wish JavaScript was a strongly-typed language — very happy.

A couple of things to keep in mind with const:

  • Const, like let, is block scoped, making it only accessible within the code block (curly braces) it’s defined in. It’s also subject to the Temporal Dead Zone rule.
        const myCat = ‘Fluffy’; //so far so good
  • Unlike let, const must be assigned a value at the time of declaration.
        const myDog;
        //whoops! “SyntaxError: Missing initializer in const declaration”
  • A const needs to be unique and cannot share its name with anything else, including a function or object, in the same scope.
        myCat = ‘Puffball’;  //whoops again!  “TypeError: Assignment to constant variable.”
  • A variable declared with const can be declared globally, but its value will not become property of the window object (as var assignments do).
  • A const declaration creates a read-only reference to a value. This doesn’t render its value immutable — it just means that the variable identifier cannot be reassigned. For instance, if the const holds an object, the object’s contents can be altered to your little heart’s content:
const myobject = {name:'George', age:39}

//so far so good. Say you need to change George’s age, though: 

myobject = {name: 'George', age:40}

//This throws an error, because you just told JS that myobject is George and he’s 39. However, 

myobject.age = 40 

//totally ok!  

console.log(myobject)

//{name: “George’, age: 40}

Now the question becomes, do we simply stop using var altogether? Even this long after ES6 go-live, var is still in wide usage; it still has a place at the JS buffet. The consensus among developers is summed up in this graphical tweet:

There you have it, a good basic introduction to three of the most useful ES6 goodies.  All kinds of other great stuff to play with in that candy shop though, including new data structures like Map and Set, as well as new Math, Number, String, Array and Object methods. ES6 also added of comprehensions (thanks again, o mighty CoffeeScript!) and activated the previously reserved keyword class, which would itself call for a dedicated article. Which, given enough “yes, please” from readers, I will be delighted to write.

Feature image by Andrew Peloso from Unsplash.


A digest of the week’s most important stories & analyses.

View / Add Comments