一篇文章带你看懂JavaScript中的模板字面量

69 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

模板字面量

ECMAScript 6新增了使用木板子面了定义字符串的能力。与使用单引号或双引号不同,模板字面量保留换行字符,可以跨行定义字符串

<script>
    let myMultiLineString = 'first line\nsecond line';
    let myMultiLineTemplateLiteral = 'first line second line';
    console.log(myMultiLineString);
    // first line
    // second line
    console.log(myMultiLineTemplateLiteral);
    // first line  second line
</script>

顾名思义,模板字面量在定义模板时特别游泳,比如下面这个HTML模板

<div>
    <a href="#">
        <span>Jake</span>
    </a>
</div>

由于木板子会保持反引号内部的空格,因此在使用时需要格外注意。格式正确的模板字符串看起来可能会缩进不当

<script>
    let myTemplateLiteral = 'first line second line';
    console.log(myTemplateLiteral.length);   // 47
    let secondTemplateLiteral = 'first line second line';
    console.log(secondTemplateLiteral[0] === '\n');   // true
    let thirdTemplateLiteral = 'first line second line';
    console.log(thirdTemplateLiteral);   // first line second line
</script>

字符串插值

模板字面量最常用的一个特性是支持字符串插值,也就是可以在一个连续定义中插入一个或多个值。技术上将,模板字面量不是字符串,而是一种特殊的JavaScript句法表达式,只不过求值后得到的是字符串,模板字面量在定义时立即求值并转换为字符串实例,任何插入的变量也会从它们最接近的作用域中取值

字符串插值通过${}中使用一个JavaScript表达式实现

<script>
  let value = 5 ;
  let exponent = 'second';
  let interpolatedString = value + 'to the ' + exponent + ' power is ' + (value * value);
  let interpolatedTemplateLiteral = '${ value } to the ${ exponent } power is ${ value * value }';
  console.log(interpolatedString);
  console.log(interpolatedTemplateLiteral);
</script>

所有插入的值都会使用toString()强制转型为字符串,而且任何JavaScript表达式都可以用于插值。嵌套的模板字符串无须转义

console.log('Hello,${'World' }!'); //Hello,World!

将表达式转换为字符串会调用toString()

let foo = {toString: () => 'World'};
console.log('Hello,${ foo }!');   // Hello ,World!

此外,模板也可以插入自己之前的值

<script>
    let value = '';

    function append() {
        value = '${value}abc'
        console.log(value);
    }

    append();  // abc
    append();  // abcabc
    append();  // abcabcabc
</script>

模板字面量标签函数

模板字面量也支持定义标签函数,而通过标签函数可以自定义插值行为。标签函数会接收被插值符号分隔后的模板和对每个表达式求值的结果

标签函数本身是一个常规函数,通过前缀到模板字面量来应用自定义行为

<script>  

  let a = 6 ;  

  let b = 9 ;  

  function simpleTag(strings , aValExpression , bValExpression , sumExpression) {  

    console.log(strings);  

  console.log(aValExpression);  

  console.log(bValExpression);  

  console.log(sumExpression);  

  return 'foobar';  

  }  

    let untaggedResult = '${ a } + $ { b }  = ${ a + b }';  

</script>

因为表达式参数的数量是可变的,所以通常使用剩余操作符(rest operator)将它们收集到一个数组中

let a = 6 ;
let b = 9 ;

对于有n个插值的模板字面量,传给标签函数的表达式参数的个数始终是n,而传给标签函数的第一个参数所包含的字符串的个数始终是n+1。因此,如果你想把这些字符串和对表达式求值的结果拼接起来作为默认返回的字符串,可以这么做

<script>
let a = 6 ;
let b = 9 ;

        function zipTag(String, ...expressions) {
            return strings[0] +
                expressions.map((e, i) => '${e}${strings[i+1]}').join('');
        }

        let untaggedResult = '${ a } + ${ b } = ${ a + b }';
        let taggedResult = zipTag`${a} + ${b} = ${a + b}`;
        console.log(untaggedResult);
        console.log(taggedResult);
    </script>