我对模版字符串中标签模板的思考

模板字符串

模板字符串的几个特性: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, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;");

    // 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>&lt;script&gt;alert("abc")&lt;/script&gt; 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"

总之,标签模板功能很强大,可能一开始并不会以为厉害之处,平时工做中也不会用到,可是在不少库中会用到它,咱们
使用这些库的时候也在不自觉中使用了标签模板,能够慢慢开始了解它,并使用它。

参考文章:

https://www.freecodecamp.org/...

https://mxstbr.blog/2016/11/s...

相关文章
相关标签/搜索