LouieLiu

Template Literals(模板字符串)

  今天碰上一道这样的题 然后想说的是关于ES6的新特性 模板字符串

Description:

You probably know the “like” system from Facebook and other pages. People can “like” blog posts, pictures or other items. We want to create the text that should be displayed next to such an item.Implement a function likes :: [String] -> String, which must take in input array, containing the names of people who like an item. It must return the display text as shown in the examples:

1
2
3
4
5
likes [] // must be "no one likes this"
likes ["Peter"] // must be "Peter likes this"
likes ["Jacob", "Alex"] // must be "Jacob and Alex like this"
likes ["Max", "John", "Mark"] // must be "Max, John and Mark like this"
likes ["Alex", "Jacob", "Mark", "Max"] // must be "Alex, Jacob and 2 others like this"

For more than 4 names, the number in and 2 others simply increases.

解法其实挺简单 通常的做法就是使用switch-case或者 if-else 来解

解法一:

1
2
3
4
5
6
7
8
9
10
function likes(names) {
names = names || [];
switch(names.length){
case 0: return 'no one likes this'; break;
case 1: return names[0] + ' likes this'; break;
case 2: return names[0] + ' and ' + names[1] + ' like this'; break;
case 3: return names[0] + ', ' + names[1] + ' and ' + names[2] + ' like this'; break;
default: return names[0] + ', ' + names[1] + ' and ' + (names.length - 2) + ' others like this';
}
}

主要要说的是关于第二种解法中的模板字符串

解法二:

1
2
3
4
5
6
7
8
9
function likes(names) {
return {
0: 'no one likes this',
1: `${names[0]} likes this`,
2: `${names[0]} and ${names[1]} like this`,
3: `${names[0]}, ${names[1]} and ${names[2]} like this`,
4: `${names[0]}, ${names[1]} and ${names.length - 2} others like this`,
}[Math.min(4, names.length)]
}

Template literals(模板字面量)

关于模板字符串MDN中这样说:

Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them. They were called “template strings” in prior editions of the ES2015 specification.


模板字符串又叫模板字面量 是允许嵌入表达式的字符串字面量 而且支持多行字符串和字符串插补特性 是ES5/ES6的新规范

语法示例:

1
2
3
4
`string line`
`string ${expression} string`
var name = "string";
console.log(`This name is a ${name} `);// " This name is a string"
1
2
3
4
5
6
7
8
var text = `this blog lives at ${'github.io'}`
console.log(text)
// 'this blog lives at github.io'
var today = new Date()
var text = `today is the ${today}`
console.log(text)
// 'today is the Sat Feb 04 2017 00:32:32 GMT+0800 (中国标准时间)'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var article = {
title: 'Hello Template Literals',
teaser: 'String interpolation is awesome. Here are some features',
body: 'Lots and lots of sanitized HTML',
tags: ['es6', 'template-literals', 'es6-in-depth']
}
var html = `<article>
<header>
<h1>${title}</h1>
</header>
<section>
<div>${teaser}</div>
<div>${body}</div>
</section>
<footer>
<ul>
${tags.map(tag => `<li>${tag}</li>`).join('\n ')}
</ul>
</footer>
</article>`

输出后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<article>
<header>
<h1>Hello Template Literals</h1>
</header>
<section>
<div>String interpolation is awesome. Here are some features</div>
<div>Lots and lots of sanitized HTML</div>
</section>
<footer>
<ul>
<li>es6</li>
<li>template-literals</li>
<li>es6-in-depth</li>
</ul>
</footer>
</article>

模板字符串使用反引号(``)来代替普通字符串的单引号双引号 模板字符串可以包含特定语法${expression}的占位符 模板字符串它们看起来与普通字符串并没有什么特别。在最简单的情况下,它们与普通字符串的表现一致 通过使用模板字符串 可以使字符串中插入值更加简便 美观

功能:

  • 可以在模板字面量中插入变量
  • 可以插入任意JavaScript表达式 并不限于变量 甚至可以在模板字符串中相互嵌套
  • 如果在其中需要使用反撇号 需要使用反斜杠转义: ‘\' ==> "“;$和{}同理
  • 支持多行插入 模板字符串中所有的空格 换行 缩进 都会原样输出在生成的字符串中
  • 如果插入的占位符不是字符串 可以将其转化为字符串 例如:如果expression为一个对象 它将会调用它的.toString()方法将其转化为字符串值

不足:

  • 不会自动转义特殊字符 为了避免xss 应当像拼接普通字符串时做的那样对非置信数据进行特殊处理
  • 没有内建循环和条件语法支持 无法遍历填充等
  • 它们不能替代模板引擎的地位

带标签的模板字符串

带标签的模板字符串是模板字符串的一种高级表达形式 它允许通过标签函数修改模板字符串的输出 标签模板的语法非常简单,在模板字符串开始的反撇号前附加一个额外的标签即可 标签函数的第一个参数是包含了字符串字面值的数组 第二个参数是在第一个参数后的每一个参数都是被替换后的表达式 最后标签函数返回处理好的字符串 其中标签函数名无特殊限制 而且标签函数不一定要返回一个字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
var a = 5;
var b = 10;
tag`Hello ${a+b} world ${a*b}`;// "Bazinga!"
function tag(strings,...values){
console.log(strings[0]);// "Hello"
console.log(strings[1]);//" world"
console.log(strings[2]);// ""
console.log(values[0]);//15
console.log(values[1]);//50
return "Bazinga!"
}

可以通过使用标签函数自行解决 模板字符串无法自动转义特殊字符的问题

1
var msg = SafterHTML`<p>${bonk.sender} 向你问好 </p>`;

上述代码等效于

1
var msg = SaferHTML(templateData, bonk.sender);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function SaferHTML(templateData) {
var s = templateData[0];
for (var i = 1; i < arguments.length; i++) {
var arg = String(arguments[i]);
// 转义占位符中的特殊字符。
s += arg.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/</g, ">");
// 不转义模板中的特殊字符。
s += templateData[i];
}
return s;
}

通过这样的定义,标签模板SaferHTML<p>${bonk.sender} 向你问好。</p> 可能扩展为字符串 “

ES6<3er 向你问好<="" p="">“。即使一个恶意命名的用户,例如“黑客Steve”,向其他用户发送一条骚扰信息,无论如何这条信息都会被转义为普通字符串,其他用户不会受到潜在攻击的威胁

补充

在标签函数的第一个参数中,存在一个特殊的属性raw ,我们可以通过它来访问模板字符串的原始字符串 另外使用String.raw() 方法创建原始字符串和使用默认模板函数和字符串连接创建是一样的

1
2
3
4
5
6
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`;

参考链接:

模板字符串
ES6 Template Literals in Depth
深入浅出ES6(四):模板字符串