这个章节会介绍更进阶的用法,也就是标籤样板字面值
首先先用一个简单的範例来带大家了解甚么是 标籤样板字面值。
function showConsole(strings, arg1) { console.log(strings, arg1);}const myName = '哈士奇';`您好 ${myName} ,餐点已经準备好噜!`
showConsole 这个函式会显示接收到的字串以及参数。
下方也有定义好的变数,以及事先準备好的样板字面值字串。
而所谓的标籤样板字面值,就是
showConsole`您好 ${myName} ,餐点已经準备好噜!`;
直接将 函式名称接在样板字面值之前
存档执行以后呢~
这样的原理到底是怎么运作的呢?
这边解释一下,我们传入第一个参数 strings
是由样板字面值拆解而来的!
那么拆解的规则就是依据我们在样板字面值中的 ${}
作为分段点
所以可以看到这边就被拆成了两段,并且放入一个阵列中
另外,arg则是 ${}
所传入的变数,如果现在样板字面值中的变数有多个的话,也会传入多个。
// 标籤样板字面值function showConsole(strings, arg1, arg2, arg3) { console.log(strings, arg1, arg2, arg3);}const myName = '哈士奇';showConsole`您好 ${myName} ,餐点已经準备好噜! ${2} ${4}`;
眼尖的人可以发现,只要参数变多,我手动设定的arg变数也要跟着变多,但有时候就是不知道会传几个参数。
这个时候就要使用前面章节也使用过的其余参数运算子(...),来盛装这些传入的参数内容!
// 标籤样板字面值function showConsole(strings, ...arg) { console.log(strings, arg);}const myName = '哈士奇';showConsole`您好 ${myName} ,餐点已经準备好噜! ${2} ${4}`;
接下来我们就透过一个小範例来让大家更了解要怎么用运用 标籤样板字面值!
範例1
情境: 我们现在希望得到一个组好的字串:
`您好 <span> 哈士奇 <span> ,餐点已经準备好噜~!`
那我们刚刚依据所学得,先做出第一部的程式码来看看~
const myName = '哈士奇';const sentence = `您好 ${myName} ,餐点已经準备好噜!`;console.log(sentence);
那么我们要针对变数加上 span 的标籤的话,就要使用标籤样板字面值,为此我们得先定义一个函式。
const myName = '哈士奇';const highlight = (strings, ...arg) =>( strings.map((str, i) => `${str}`));const sentence = highlight`您好 ${myName} ,餐点已经準备好噜!`;console.log(sentence);
定义好之后,我们针对 strings 进行 map 的迴圈,最后会回传一个新的阵列。
并且先把 str 印出来,看看是不是被拆解的字串
很好,如我们预期的,只有先是字串的阵列,那么这个时候我们再使用join,将阵列转为字串,同时去除掉逗号。
const myName = '哈士奇';const highlight = (strings, ...arg) =>( strings.map((str, i) => `${str}`).join(''));const sentence = highlight`您好 ${myName} ,餐点已经準备好噜!`;console.log(sentence);
到这边已经準备得差不多,字串也组好了!
接着下一步就是加入传入的变数!
const myName = '哈士奇';const highlight = (strings, ...arg) =>( strings.map((str, i) => `${str} <span>${arg[i]}</span>`).join(''));const sentence = highlight`您好 ${myName} ,餐点已经準备好噜!`;console.log(sentence);
只差一点点了,为什么最后面会出现 undefined 呢?
原因是因为,strings 的阵列有两个内容,但是 arg 的阵列只有一个参数传入,所以当他找 arg[1]
的时候取不到值,只好回传 undefind。
这个时候该怎么半呢?
这个时候我们就可以透过 三元运算子 来判断这个值存不存在!
const myName = '哈士奇';const highlight = (strings, ...arg) =>( strings.map((str, i) => `${str} ${arg[i] ? `<span>${arg[i]}</span>` : '' }`).join(''));const sentence = highlight`您好 ${myName} ,餐点已经準备好噜!`;console.log(sentence);
这样子就可以完成我们想要的结果噜!
你可能会想说,为什么需要这么麻烦,一开始加上去不就好了吗?
的确是这样没错,但当变数一多的时候,直接套用就会比较方便喔!
範例2
现在我们是一个应用程式的开发者,现在有很多使用者会来传入讯息。
const messageName = '小明';document.querySelector('#message').innerHTML = `<p>${messageName}</p>传来一则讯息!`
但是这样的情况很容易造成 XSS 攻击,简单来说就是透过自定义的内容插入一些恶意的js程式,窃取用户的个资或其他非开发者预期的行为。
// const messageName = '小明';const messageName = '<img onload="fetch(\'https://randomuser.me/api/\')" src="https://images.unsplash.com/photo-1587613842352-3022a317a088?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80" alt=""/>'document.querySelector('#message').innerHTML = `<p>${messageName}</p>传来一则讯息!`
原本应该是出现人名的地方却传来了一张图片!
更可怕的是使用 onload的属性,有可能使用ajax或是把资料传送给第三方的网站。
这个时候我们就可以使用标籤样板字面值来把因为变数传进来的有恶意的字串给换掉,防止XSS 攻击
function convertHTMLXSS(strings, ...keys) { return strings.map((str, i) => ( `${str}${keys[i] ? `${keys[i] .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, ''') .replace(/\//g, '/') }` : ''}` )).join('');}const messageName = '<img onload="fetch(\'https://randomuser.me/api/\')" src="https://images.unsplash.com/photo-1587613842352-3022a317a088?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80" alt=""/>'document.querySelector('#message').innerHTML = convertHTMLXSS`<p>${messageName}</p>传来一则讯息!`
以上就是标籤样板字面值的介绍,没有问题的话大家也可以试着想想看哪里可以应用到标籤样板字面值喔!
没问题的话就继续往下个章节吧~汪汪~!