The following is an excerpt from ECMAScript 6 Succinctly, written by Matthew Duffield. Look for this upcoming title to be added in late June to the Succinctly series—Syncfusion’s free library of pithy technology books.
ECMAScript 6 (ES6), also known as ECMAScript 2015, brings new functionality and features to the table that developers have been wanting for a long time. The wait is over, and you can now develop all of these features. The really good news is that you can also target browsers that don’t even support ES6 yet by using a transpiler. A compiler translates one language to another, such as C# to MSIL, while a transpiler converts one version of a language to another, such as ES6 to ES5.
Most modern languages provide some method of defining a constant. This ensures that the value of the variable never changes and is a great optimization usage for values you know will never change in your applications.
Code Listing 5
const PI = 3.141593; console.log(PI);
The code produces the following output in Sublime using Ctrl+B for Windows or Cmd+B for Mac:
Code Listing 6
3.141593
Now, let’s try and re-assign a value to the PI variable. We can do this by adding the following lines to the editor:
Code Listing 7
PI = 22; console.log(PI);
Trying to run the previous example will produce a syntax error. The transpiler is smart enough to give us the reason why. Take a look at the following image:
You can see in Figure 2 that since PI was declared as a constant, it is considered read-only. This is good and the error description is very clear.
Code Listing 8
var submit = function() { var x = "foo";
if (x == "foo") { var y = "bar"; } console.log(x); console.log(y); } submit();
The code produces the following output:
Code Listing 9
foo bar
As you can see from the output, both x and y variables are available at the function level. This is known as hoisting regardless of the logical blocks.
With the let keyword, this is now different. Let’s modify the previous code listing, but use the let keyword when declaring the y variable:
Code Listing 10
var submit = function() { var x = "foo"; if (x == "foo") { let y = "bar"; } console.log(x); console.log(y); } submit();
The code produces the following output in Chrome after clicking on the Run button:
Code Listing 11
"ReferenceError: y is not defined
This output is actually pretty good in that it lets us know that we are trying to reference a variable that is out of scope.
The following example demonstrates how the let operator works inside for-loops:
Code Listing 12
let shoppingCart = [ {id: 0, product: "DVD", price: 21.99}, {id: 1, product: "CD", price: 11.99} ]; for (let i = 0; i < shoppingCart.length; i++) { let item = shoppingCart[i]; console.log("Item: " + item.product + " - Price: " + item.price); }
Let us look at the output that is produced:
Code Listing 13
Item: DVD - Price: 21.99 Item: CD - Price: 11.99
As you can see, we still get the expected behavior, but the item variable has a scope boundary of the for-loop.
When using a transpiler, this alone will help mitigate many scoping issues that were error-prone in ES5 with hoisting.
Two new flags are introduced in ES6 for regular expressions
var text = 'First line\nsecond line'; var regex = /^(\S+) line\n?/y; var match = regex.exec(text); console.log(match[1]); // logs 'First' console.log(regex.lastIndex); // logs '11' var match2 = regex.exec(text); console.log(match2[1]); // logs'Second' console.log(regex.lastIndex); // logs '22' var match3 = regex.exec(text); console.log(match3 === null); // logs 'true'
We start out with a simple string in the text variable. Next, we define our regular expression. As you can see, we are looking for matches that end with “line” and possibly a new line. We then execute the regular expression and grab the first match which contains the value First and also logs the lastIndex position.
We run the exec method on the text variable again and it continues from the lastIndex position and finds the “Second” match. The lastIndex position is updated and logged.
Finally, we run the exec method a third time, and it returns null, indicating no more matches were found.
The main use case for this new flag is tokenizing, where you want each match to immediately follow its predecessor.
The following is an example of tokenizing a string:
Code Listing 15
const TOKEN = /\s*(\+|[0-9]+)\s*/y; function tokenize(TOKEN_REGEX, str) { let result = []; let match; while (match = TOKEN_REGEX.exec(str)) { result.push(match[1]); } return result;
} let result = tokenize(TOKEN, '3 + 4'); console.log(JSON.stringify(result));
Here is the output it produces:
Code Listing 16
["3","+","4"]
Although this is a contrived example, you can see where this could come in very handy when wanting to tokenize strings.
The /u flag puts the regular expression into a special Unicode mode. This mode has two features:
Code Listing 17
console.log('\u{1F680}' === '\uD83D\uDE80'); let codepoint = "\u{1F680}"; console.log(codepoint);
Executing this produces the following result:
Code Listing 18
True
The first line of code demonstrates comparing a Unicode code point against two normal Unicode escapes. The second and third lines simply demonstrate how you can render the Unicode code point.