Skip to main content

Template Strings_ES6 Notes 3

Free2016-04-10#JS#JS模板字符串#JS反撇号#JS标签模板#template string#template inception#tagged template

The most open feature in ES6, not just simple string concatenation

1. Function and Syntax

Template strings are used to implement string interpolation, more convenient and elegant than plus (+) concatenation

`${expr}` syntax provides string interpolation functionality

Note: The ` (backtick, located below Esc on keyboard) above is part of template string syntax, not wrong markdown usage

P.S. I encountered the first problem, backtick conflicts with markdown syntax, there are two choices, either use markdown feature of multi-line backticks as code delimiter (wrap code with two consecutive backticks, but the markdown plugin I use doesn't support this rare syntax), or use code tag, for example the markdown source code above is <code>\`${expr}\`</code>

For example:

function req(user, action) {
    // if !isValid
    error(`user ${user} failed to do action ${action}`);
}
function error(str) {
    console.log(str);
}
// test
req('Sam', 'login');    // user Sam failed to do action login

2. Characteristics

Including variables, literals, function calls, etc., but doesn't support flow control (branch/loop), so template strings cannot replace template engines

For example:

// Doesn't support branch/loop
// console.log(`${if (2 > 1) {str}}`);  // Uncaught SyntaxError: Unexpected token if
// console.log(`${for (; false;) {}}`); // Uncaught SyntaxError: Unexpected token for

var outer = 'outer';
var inner = 'inner';
var str = `
\$\{
    ${
        outer   // variable
        +       // + concatenation
        `\$\{
            ${inner}    // interpolation
        \}`
    }
\}
`;

var h5 = document.querySelector('#h5');
var pre = document.querySelector('#pre');
h5.innerHTML = str;
pre.innerHTML = str;

Display result is as follows:

// #h5
${ outer${ inner // interpolation } }
// #pre
${
    outer${
            inner    // interpolation
        }
}

3. Can Be Written Across Multiple Lines

But comments (single-line/multi-line) may act on the entire string, or directly appear as literals in the result string. All spaces, newlines, indentation in template strings will be output as-is in the generated string (pre is different from other elements), specifically see example above

4. Special Characters Need Escaping

3 special characters[`${] (regex form) need escaping, specifically see example above

P.S. Right curly brace doesn't need escaping, of course, escaping it is also fine. But the 3 above must be escaped

5. No Automatic Processing

Won't automatically filter unsafe tags, won't automatically escape special characters, also need to prevent xss attacks, although provides tagged templates, but not very convenient

For example:

// xss attack
var userInput = '<a href="" onclick="alert(\'xss attack\');">Claim Reward</a>';
var input = document.querySelector('#input');
input.innerHTML = `User Input: ${userInput}`;

Code above will generate a link, clicking alerts "xss attack", can customize process template strings through tagged templates, such as filtering out unsafe characters, as follows:

// Define template tag
function myFilter(templateData) {
    var aStr = templateData;        // String array split by ${} interpolation
    var aRaw = templateData.raw;    // Unescaped original string (\n)
    var aVar = Array.prototype.slice.call(arguments, 1);    // Interpolation variable array
    console.log(aStr);
    console.log(aRaw);
    console.log(aVar);

    // filter vars
    aVar.forEach(function(item, index, arr) {
        arr[index] = item.replace(/(<[^>]*>)/i, '');
    });
    var res = '';
    var i = 0;
    aStr.forEach(function(item) {
        res += item;
        if (aVar[i]) {
            res += aVar[i++];
        }
    });

    return res;
}

// Use tagged template
var safeInput = document.querySelector('#safe_input');
safeInput.innerHTML = myFilter`User Input:\n${userInput}`;
// Equivalent to
// safeInput.innerHTML = myFilter(['User Input:'], userInput);

Tag appears before template string, is a simplified function call, template tag is similar to callback function, parameter templateData format is determined, take data from parameters, process and return

But defining template tags still feels quite troublesome, but this is a very attractive feature,预示着 a powerful string processing library (escape special characters, i18n, word count, etc.)

6. Flexibility

Tagged template's return value doesn't have to be string, can be any value. This means not only will a powerful "string" processing library appear, any library can perfectly embed into JS in this form, especially things like shader language that currently has unfriendly form in JS... After other languages appear attractive features, can perfectly implant into JS, can even use this to implement your own language (template tag's function body is interpreter)

Tagged templates bring great flexibility, can use custom tags to create regular expressions, DOM trees, images, entire asynchronous process represented by promises, JS data structures, GL shaders...

Quote original text from reference materials:

Tagged templates welcome library designers with open arms to create powerful domain-specific languages. These languages may not look like JS, but they can still be seamlessly embedded into JS and intelligently interact with other JS language features. I don't know where this feature will lead us, but it contains infinite possibilities, which makes me extremely excited!

3. Summary

Template strings look like syntax sugar, actually opened a door, indicating JS welcomes the future with open attitude

Remember [seniors discussing yield 5 years ago](/articles/javascript 实现 yield/)? At that time how much they hoped for such a feature, wasn't the original intention of discussing this problem hoping JS could get C#'s yield feature?

Reference Materials

  • "ES6 in Depth": Free e-book provided by InfoQ Chinese station

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment