Wednesday, September 23, 2015

Template Strings - New in Node 4

Today on Amphibian.com, the frogs try to get past ad blockers by interleaving the text of ads with the rest of the text on their website. But since their website is their comic about their website (see Monday's topic - meta), there are problems.

Similarly, when you want to put the values of variables or other expressions in your JavaScript strings you probably do something like this:

var str1 = "some static text and " + someVar + " and some more text";

JavaScript Strings, circa 1905
A cool new ES6 feature now available in Node 4 is the Template String, which can make the above code a little nicer.

Template Strings are a new way of creating strings with embedded expressions. These expressions can be simply variables, formulas, or function calls. To make a Template String, use the back-tick ` (the thing that shares the key with ~ on an American English keyboard) instead of the regular tick ' or double-quote ". Inside, put expressions inside curly braces { } prefixed with a dollar sign $.

Here's an example.

var frogType = "Science";
var numFlies = 42;

console.log("The " + frogType + " frog caught " + numFlies + " flies");
console.log(`The ${frogType} frog caught ${numFlies} flies`);

Both messages print out exactly the same, but the second one, using a Template String, is shorter and looks nicer. I think it helps keep your code cleaner.

Another feature of Template Strings is that they can include literal new-lines. Look at this:

var str1 = "this is string 1\n" +
           "with two lines";

var str2 = `this is string 1
with two lines`;

console.log(str1);
console.log(str2);

console.log(str1 === str2); // prints true

The str2 variable is created by simply starting a new line in the middle of the string instead of embedding the \n. Also note that the two strings are equal when compared, despite being created in different ways. Personally, I'm not sold on this particular attribute of Template Strings. I think putting literal new-lines in there hurts the readability of the code, but you might not have a problem with it. Just throwing it out there!

Obviously, using this technique to include variable values in strings is useful. But you can put more complex expressions inside the braces.

var a = 2;
var b = 4;
console.log(`the product is ${a * b}`);

The code above prints the product of a and b by performing the multiplication in the Template String. But please note that the expression is only evaluated once, when the string is created. The following code exemplifies that:

var c = 3;
var d = 7;
var str3 = `the sum is ${c + d}`;

console.log(str3); // the sum is 10

d = 14;

console.log(str3); // the sum is 10

Changing the value of d after str3 has been created does not change the value of str3. Be careful, however, because the process of creating a Template String can change the values of your variables - just like if you did things the old-fashioned way.

var e = 1;
console.log(`the variable e = ${e++}`);

console.log(e); // prints 2

In the above code, printing out the Template String changed the value of e. Maybe this is what you want...maybe it's not. Be mindful.

But wait! There's more!

Template Strings also support tagging, meaning that they can be passed to a function which can modify their output. This feature is a bit unusual.

To use tagging, simply define a string processor function which should expect to receive as arguments
  1. a string array containing the "normal" parts of the Template String
  2. zero or more additional arguments, each representing an expression value
The tagging function should return a string, which is probably going to be some version of the data passed to it, but doesn't have to be related at all! Here's an example.

var test1 = 33;
var test2 = 44;

function tag(strings) {

    // print the static parts, in order
    strings.forEach(function(s) {
        console.log(s);
    });

    // print the expression values, if any
    if (arguments.length > 1) {
        for (var i = 1; i < arguments.length; i++) {
            console.log(arguments[i]);
        }
    } else {
        console.log("no expressions!");
    }

    // this will be the tagged string value
    return "not the string you're looking for";

}

console.log(tag `Part 1 ${test1} part 2 ${test2}`);
console.log(tag `what? no expressions?`);

I've called my tagging function tag, but it can be anything you want. This first example just prints out the parts of the Template String so you can see how it works. It totally ignores the real contents of the Template String and returns nonsense. Those two calls to console.log both print the return value from tag. Probably not useful, but shows you what can be done. I honestly haven't thought of a legitimate use for tagging yet, but I might someday. Maybe you already know of one?

And there you have it. Template Strings, the good and the weird. I think the hardest part will be hitting that back-tick key. Not used to typing that one...

Amphibian.com comic for 23 September 2015