模板字符串的几个特性:javascript
//嵌入变量 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)
若是模板字符串中含有变量,标签模板会进行特殊处理,它会根据嵌入的变量,把模板字符串拆开,
普通字符串组成数组作位第一个参数,插入的变量依次做为第二个、第三个...变量。java
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函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,也就是说,变量替换只发生在数组的第一个成员与第二个成员之间、第二个成员与第三个成员之间,以此类推。es6
tag函数的其余参数,都是模板字符串各个变量被替换后的值。因为本例中,模板字符串含有两个变量,所以tag会接受到value1和value2两个参数。数组
我第一次看到标签模板的时候,不由在想为何要有标签模板,它有什么普通函数不能替代的地方呢?若是没有不可替代的地方,那为何还要创造
它呢?
答案是:标签模板确实有它存在的意义,也有普通函数没法替代它的地方。函数
const logArgs = (...args) => console.log(...args)
先用普通函数形式调用this
logArgs('a', 'b') // -> a b
再用一个简单的模板字符串试试:spa
logArgs`` // -> ["", raw: Array(1)]
上面输出了一个空数组,而后传入一个有值的模板字符串:code
logArgs`I like pizza` // -> ["I like pizza"]
如今,进一步网模板字符串中传入变量component
const favoriteFood = 'pizza' //看成普通函数调用,直接出入拼接的字符串 logArgs(`I like ${favoriteFood}.`) // -> I like pizza. //使用标签模板,会输出处理后的参数 const favoriteFood = 'pizza' logArgs`I like ${favoriteFood}.` // -> ["I like ", "."] "pizza"
变换过程是这样的:blog
当咱们传入多个变量时,每个插入的变量都做为下一个参数了
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"
总之,标签模板功能很强大,可能一开始并不会以为厉害之处,平时工做中也不会用到,可是在不少库中会用到它,咱们
使用这些库的时候也在不自觉中使用了标签模板,能够慢慢开始了解它,并使用它。
参考文章: