模板字符串(模板字面量)的使用

警告:这是一个ECMA2015/ES6的特性,使用时请务必注意浏览器兼容性

介绍(introduction)

说起模板字符串不免就要想起有些编程语言中,那个些封装良好的模板字符串啦,不过这里暂且不提,对于js,有许多模板引擎也提供相似的服务,但总比不上原生支持来的爽快,在es6的官方解释中,这个特性被归为一个小类Template Literals(模板字面量12.2.9),这里我要介绍的内容只是这块知识中的一个小小的章节(12.2.9.1 Static Semantics: TemplateStrings 基本语法:模板字符串)

1 基本用法

`string text`;

`string text line 1
string text line 2`;
//下面两句不能执行,只是示意一下基本的语法格式
//对应解释①处
`string text ${expression} string text`;
//对应解释②处
tag `string text ${expression} string text`;
//对应解释③处
`\`` === "`"; // --> true

从一开始接触js到现在对于\n这个东西有种说不清道不明的厌恶,不怪乎无法简明的看出是否换行,这次的模板字符串带来了一些便利,此外就是表达式最常用的模板字符的替换,这里的expression可以是任何js表达式。

2. 官方的解释

模板字符串简单的讲就是使用着重符号(`)而不是单/双引号包裹的字符串,在其中可以使用一种由美元符号做开头后面衔接花括号包裹表达式(${expression})的方法来做占位符使用①,占位符中的内容以及外部的string将可以作为一个特殊的参数传递给一个函数,如果一个模板字符串开头存在一个方法(函数),那么这个函数在输出最终结果前,你都可以在通过该函数对模板字符串来进行操作处理。②

如果你想从着重符中跳出,那么和正常的转义字符一样你可以使用\`来实现。③

3. 实例演示

3.1 多行字符串

var str = "string text line 1\nstring text line 2";
console.log(str);
// "string text line 1
// string text line 2"
//=>现在可以使用下面的方法代替
var str = `string text line 1
string text line 2`;
console.log(str);
// "string text line 1
// string text line 2"

3.2 表达式的间补

var a = 1;
var b = 2;
console.log("one plus two is " + (a + b) + " and\nnot " + (2 * a + b) + ".");
//"one plus two is 3 and
//not 4."

//现在我们有更加优雅的方式了(其实也没好到哪里去)
var a = 1;
var b = 2;
console.log(`one plus two is ${a + b} and
not ${2 * a + b}.`);
//"one plus two is 3 and
//not 4."

3.3 带标签字面量

var a = 5;
var b = 10;
//这里使用了不定参数的方法(不定参数具体哪里介绍的我也不记得了,早期使用的是arguments的方法来获取,但现在可以使用不定参数快捷的取得)
function tag(strings, ...values) {
  //你可以在这里执行任意多的方法对内容作出处理
  console.log(strings[0]); // "Hello "
  console.log(strings[1]); // " world "
  console.log(values[0]);  // 15
  console.log(values[1]);  // 50
  //返回值将会作为最后输出
  return "Bazinga!";
}

tag`Hello ${ a + b } world ${ a * b}`;
// "Bazinga!"

这里指的注意的是:

  1. string获得的是一个特殊的数组,且长度最小为1
  2. string有且必定包含有raw为键的一个数组,这个数组的长度必定和string数组的长度一致
  3. values也是一个数组,但是他可能是一个空数组[]

在mdn上,原作者提出了一个更加良好的方法来处理一下特殊的情况比如让他处理一个对象。

function template(strings, ...keys) {
  return (function(...values) {
    var dict = values[values.length - 1] || {};
    var result = [strings[0]];
    keys.forEach(function(key, i) {
      var value = Number.isInteger(key) ? values[key] : dict[key];
      result.push(value, strings[i + 1]);
    });
    return result.join('');
  });
}
var t1Closure = template`${0}${1}${0}!`;
t1Closure('Y', 'A');  // "YAY!" 
var t2Closure = template`${0} ${'foo'}!`;
t2Closure('Hello', {foo: 'World'});  // "Hello World!"

3.4 原始字符串

当然咯这里也存在一个方法允许你直接访问原始字符串。
你可以使用以下两种方法

  1. String.raw()
  2. function template(strings, …keys){return strings.raw;}

通过这种方法你可以获得一个转义之前的字符串

function tag(strings, ...values) {
  console.log(strings.raw[0]); 
  // "string text line 1 \n string text line 2"
}

tag`string text line 1 \n string text line 2`;

3.5 循环输出问题

常见的表单构造通常需要输入一个数组或对象来循环输出一个表格等等,这种应用环境下,由于模板字符串没有任何内建循环语法,无法直接坐到,不过你可以通过带标签字面量的形式来做到。

3.6 访问安全性问题

由于模板中允许字符串的赋值等等,所以理论上模板字符串是可能存在安全性问题的,所以不应当给予不受信任的程序访问。

比如

`${console.log("this is",this)}`;
//window
var a = 1;
`${a+=1}`;
//2
console.log(a);
//2

基于这个原理造成的xss(跨站脚本攻击)是完全可能的,站在安全角度来说我们最好在使用时对于字符串作出一定的转义比如通过手动的replace,或者自动的escape或者encodeURI等方法都是完全可行的。

3.7 此外就是……markdown!

对于markdown我们通常使用```做代码的分割,这当然带了一个问题那就是我们没法输出。。。

当然咯有人已经解决了这个问题点击->这里的gist 就可以看到具体的解决方案就酱!

本文标题:模板字符串(模板字面量)的使用

本文链接:https://iceprosurface.com/2016/10/01/2016/2016-10-01-template-literals/index.html

作者授权:除特别说明外,本文由 icepro 原创编译并授权刊载发布。

版权声明:本文使用「署名-非商业性使用-相同方式共享 4.0 国际」创作共享协议,转载或使用请遵守署名协议。