模板字符串
- 传统的 JavaScript 语言,输出模板通常是这样写的(下面使用了 jQuery 的方法)。
 
            
            
              javascript
              
              
            
          
          $('#result').append(
  'There are <b>' + basket.count + '</b> ' +
  'items in your basket, ' +
  '<em>' + basket.onSale +
  '</em> are on sale!'
);
        上面这种写法相当繁琐不方便,ES6 引入了模板字符串解决这个问题。
            
            
              javascript
              
              
            
          
          $('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);
        - 模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
 
            
            
              javascript
              
              
            
          
          // 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
 not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
        - 上面代码中的模板字符串,都是用反引号表示。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
 
            
            
              javascript
              
              
            
          
          let greeting = `\`Yo\` World!`;
        - 如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
 
            
            
              javascript
              
              
            
          
          $('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`);
        - 上面代码中,所有模板字符串的空格和换行,都是被保留的,比如
- 标签前面会有一个换行。如果你不想要这个换行,可以使用trim方法消除它。
 
 
            
            
              javascript
              
              
            
          
          $('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`.trim());
        - 模板字符串中嵌入变量,需要将变量名写在${}之中。
 
            
            
              javascript
              
              
            
          
          function authorize(user, action) {
  if (!user.hasPrivilege(action)) {
    throw new Error(
      // 传统写法为
      // 'User '
      // + user.name
      // + ' is not authorized to do '
      // + action
      // + '.'
      `User ${user.name} is not authorized to do ${action}.`);
  }
}
        - 大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
 
            
            
              javascript
              
              
            
          
          let x = 1;
let y = 2;
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"
let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"
        - 模板字符串之中还能调用函数。
 
            
            
              javascript
              
              
            
          
          function fn() {
  return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar
        - 
如果大括号中的值不是字符串,将按照一般的规则转为字符串。比如,大括号中是一个对象,将默认调用对象的toString方法。
 - 
如果模板字符串中的变量没有声明,将报错。
 
            
            
              javascript
              
              
            
          
          // 变量place没有声明
let msg = `Hello, ${place}`;
// 报错
        - 由于模板字符串的大括号内部,就是执行 JavaScript 代码,因此如果大括号内部是一个字符串,将会原样输出
 
            
            
              javascript
              
              
            
          
          `Hello ${'World'}`
// "Hello World"
        - 模板字符串甚至还能嵌套。
 
            
            
              javascript
              
              
            
          
          const tmpl = addrs => `
  <table>
  ${addrs.map(addr => `
    <tr><td>${addr.first}</td></tr>
    <tr><td>${addr.last}</td></tr>
  `).join('')}
  </table>
`;
        上面代码中,模板字符串的变量之中,又嵌入了另一个模板字符串,使用方法如下。
            
            
              javascript
              
              
            
          
          const data = [
    { first: '<Jane>', last: 'Bond' },
    { first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));
// <table>
//
//   <tr><td><Jane></td></tr>
//   <tr><td>Bond</td></tr>
//
//   <tr><td>Lars</td></tr>
//   <tr><td><Croft></td></tr>
//
// </table>
        如果需要引用模板字符串本身,在需要时执行,可以写成函数。
            
            
              javascript
              
              
            
          
          let func = (name) => `Hello ${name}!`;
func('Jack') // "Hello Jack!"
        上面代码中,模板字符串写成了一个函数的返回值。执行这个函数,就相当于执行这个模板字符串了。
实例:模板编译
下面,我们来看一个通过模板字符串,生成正式模板的实例。
            
            
              javascript
              
              
            
          
          let template = `
<ul>
  <% for(let i=0; i < data.supplies.length; i++) { %>
    <li><%= data.supplies[i] %></li>
  <% } %>
</ul>
`;
        上面代码在模板字符串之中,放置了一个常规模板。该模板使用<%...%>放置 JavaScript 代码,使用<%= ... %>输出 JavaScript 表达式。
怎么编译这个模板字符串呢?
一种思路是将其转换为 JavaScript 表达式字符串。
            
            
              javascript
              
              
            
          
          echo('<ul>');
for(let i=0; i < data.supplies.length; i++) {
  echo('<li>');
  echo(data.supplies[i]);
  echo('</li>');
};
echo('</ul>');
        这个转换使用正则表达式就行了。
            
            
              javascript
              
              
            
          
          let evalExpr = /<%=(.+?)%>/g;
let expr = /<%([\s\S]+?)%>/g;
template = template
  .replace(evalExpr, '`); \n  echo( $1 ); \n  echo(`')
  .replace(expr, '`); \n $1 \n  echo(`');
template = 'echo(`' + template + '`);';
        然后,将template封装在一个函数里面返回,就可以了。
            
            
              javascript
              
              
            
          
          let script =
`(function parse(data){
  let output = "";
  
  function echo(html){
    output += html;
  }
  
  ${ template }
  return output;
})`;
return script;
        将上面的内容拼装成一个模板编译函数compile。
            
            
              javascript
              
              
            
          
          function compile(template){
  const evalExpr = /<%=(.+?)%>/g;
  const expr = /<%([\s\S]+?)%>/g;
  template = template
    .replace(evalExpr, '`); \n  echo( $1 ); \n  echo(`')
    .replace(expr, '`); \n $1 \n  echo(`');
  template = 'echo(`' + template + '`);';
  let script =
  `(function parse(data){
    let output = "";
    function echo(html){
      output += html;
    }
    ${ template }
    return output;
  })`;
  return script;
}
        compile函数的用法如下
            
            
              javascript
              
              
            
          
          let parse = eval(compile(template));
div.innerHTML = parse({ supplies: [ "broom", "mop", "cleaner" ] });
//   <ul>
//     <li>broom</li>
//     <li>mop</li>
//     <li>cleaner</li>
//   </ul>