模板字符串
模板字符串的几个特性:
- 可以嵌入变量,或者表达式
- 会保留多个空格、换行、缩进
//嵌入变量
var name = "Kyle";
var greeting = `Hello ${name}!`;
console.log( greeting ); // "Hello Kyle!"
//多行
var text =
`Now is the time for all good men
to come to the aid of their
country!`;
console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!var text =
//插入表达式
function upper(s) {
return s.toUpperCase();
}
var who = "reader";
var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;
console.log( text );
// A very WARM welcome
// to all of you READERS!
标签模板
模板字符串还可以跟在一个函数后面,该函数将被调用来处理这个模板字符串。这被称为"标签模板"功能。
alert`123`
// 等同于
alert(123)
如果模板字符串中含有变量,标签模板会进行特殊处理,它会根据嵌入的变量,把模板字符串拆开。
普通字符串组成数组做位第一个参数,插入的变量依次作为第二个、第三个...变量。
var a = 5;
var b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
function tag(stringArr, value1, value2){
// ...
}
// 等同于
function tag(stringArr, ...values){
// ...
}
tag函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,也就是说,变量替换只发生在数组的第一个成员与第二个成员之间、第二个成员与第三个成员之间,以此类推。
tag函数的其他参数,都是模板字符串各个变量被替换后的值。由于本例中,模板字符串含有两个变量,因此tag会接受到value1和value2两个参数。
为什么要有标签模板?
我第一次看到标签模板的时候,不禁在想为什么要有标签模板,它有什么普通函数不能替代的地方呢?如果没有不可替代的地方,那为什么还要创造
它呢?
答案是:标签模板确实有它存在的意义,也有普通函数无法替代它的地方。
const logArgs = (...args) => console.log(...args)
先用普通函数形式调用
logArgs('a', 'b')
// -> a b
再用一个简单的模板字符串试试:
logArgs``
// -> ["", raw: Array(1)]
上面输出了一个空数组,然后传入一个有值的模板字符串:
logArgs`I like pizza`
// -> ["I like pizza"]
现在,进一步网模板字符串中传入变量
const favoriteFood = 'pizza'
//当作普通函数调用,直接出入拼接的字符串
logArgs(`I like ${favoriteFood}.`)
// -> I like pizza.
//使用标签模板,会输出处理后的参数
const favoriteFood = 'pizza'
logArgs`I like ${favoriteFood}.`
// -> ["I like ", "."] "pizza"
变换过程是这样的:
当我们传入多个变量时,每一个插入的变量都作为下一个参数了
const favoriteFood = 'pizza'
const favoriteDrink = 'obi'
logArgs`I like ${favoriteFood} and ${favoriteDrink}.`
// -> ["I like ", " and ", "."] "pizza" "obi"
这样看来,标签模版有什么大的作用呢?
//普通函数
logArgs(`Test ${() => console.log('test')}`)
// -> Test () => console.log('test')
console.log(() => console.log('test'))
// () => console.log('test')
普通函数,遇到变量是一个函数是,会把函数变成字符串形式的,而没有别的处理,看看标签模板的特殊之处,模板字符串中嵌入变量
logArgs`Test ${() => console.log('test')}`
// -> ["Test", ""] () => console.log('test')
可以看出,标签模板把模板字符串中的变量解析了出来,函数还是一个函数不会变成字符串。我们有能力拿到函数,那么我们也可以执行这个函数
const execFuncArgs = (...args) => args.forEach(arg => {
if (typeof arg === 'function') {
arg()
}
})
上面的函数,我们会忽略不是函数的参数,是函数就执行它
execFuncArgs('a', 'b')
// -> undefined
execFuncArgs(() => { console.log('this is a function') })
// -> "this is a function"
execFuncArgs('a', () => { console.log('another one') })
// -> "another one"
让我们把它当作普通函数来调用带有变量的模板字符串
execFuncArgs(`Hi, ${() => { console.log('Executed!') }}`)
// -> undefined
为什么会是undfined
呢?因为,普通函数调用的方式,模板字符串会全部变成字符串的形式,变量也变成了字符串的形式
实际上调用参数是这样的: "Hi, () => { console.log('I got executed!') }".
把上面的函数当作"标签模板"来调用
execFuncArgs`Hi, ${() => { console.log('Executed!') }}`
// -> "Executed!"
与之前相反,execFuncArgs
的第二个参数实际上是一个函数,然后会执行这个函数。
由此可以解决我的疑问了:
标签模板可以对传入的模板字符串中的变量,进行提取,并进一步处理,普通函数根本取不到这些变量,就甭提进一步处理了。
标签模板的实际应用
“标签模板”的一个重要应用,就是过滤HTML字符串,防止用户输入恶意内容。
var message =
SaferHTML`<p>${sender} has sent you a message.</p>`;
function SaferHTML(templateData) {
var s = templateData[0];
for (var i = 1; i < arguments.length; i++) {
var arg = String(arguments[i]);
// Escape special characters in the substitution.
s += arg.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
// Don't escape special characters in the template.
s += templateData[i];
}
return s;
}
上面代码中,sender变量往往是用户提供的,经过SaferHTML函数处理,里面的特殊字符都会被转义。
var sender = '<script>alert("abc")</script>'; // 恶意代码
var message = SaferHTML`<p>${sender} has sent you a message.</p>`;
message
// <p><script>alert("abc")</script> has sent you a message.</p>
标签模板的另一个应用,就是多语言转换(国际化处理)。
i18n`Welcome to ${siteName}, you are visitor number ${visitorNumber}!`
// "欢迎访问xxx,您是第xxxx位访问者!"
还有common-tags
库中的oneLine
标签函数
import {oneLine} from 'common-tags'
oneLine`
foo
bar
baz
`
// "foo bar baz"
总之,标签模板功能很强大,可能一开始并不会觉得厉害之处,平时工作中也不会用到,但是这些知识是有用的,在很多库中会用到它,我们
使用这些库的时候也在不自觉中使用了标签模板,可以慢慢开始了解它,并使用它。
参考文章:
ES6 Tagged Template Literals
The magic behind ? styled-components
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。