前端练习48 字体高亮函数

关于标签模板的练习题

知识点

标签模板

题目

完成highLight函数,可以把模板字符串中的插入内容替换掉,并且插入文档后显示红色,例如:

1
2
3
const yourName = 'ScriptOJ'
const myName = 'Jerry'
document.body.innerHTML = highlight`Hello, ${yourName}. I am ${myName}.`

CSS样式:

1
2
3
.red {
color: red
}

实现

上面的关键是函数调用那一行:

1
highlight`Hello, ${yourName}. I am ${myName}.`

以我浅薄的学识,认为是题目出错了,哪有这样进行函数调用的,所以自作主张按照下面的调用方式实现:

1
highlight('Hello, ${yourName}. I am ${myName}.')

按照这种形式,以前联系过类似的问题,使用new Function可以实现替换模板字符串变量的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
const highlight = (str) => {
let reg = /\$\{(.+?)\}/g;
let match = reg.exec(str);
let result = [];
while(match) {
result.push(match[1]);
match = reg.exec(str);
}
return str.replace(reg, (match, p1) => {
const string = new Function(...result, `return ${p1}`)(...result.map(v => eval(v)));
return `<span class="red">${string}</span>`
})
};

但是实际上,题目根本没有出错,就是这样的调用形式:

1
highlight`Hello, ${yourName}. I am ${myName}.`

这种调用形式叫做==标签模板==功能。

标签模板功能

模板字符串可以紧跟在一个函数后面,函数将被用来处理这个模板字符串,这就是标签模板功能:

1
2
3
alert`123`
// 等同于
alert(123)

标签模板其实不是模板,而是函数调用的一种形式,函数后面紧跟的字符串就是函数的参数。

当字符串中有变量时,会将模板字符串处理为多个参数,再调用函数,比如:

1
2
3
4
5
6
const a = 5;
const b = 10;

alert`hello ${a + b} world ${a * b}`
// 等同于
alert(['hello ', ' world', ''], 5, 10)

alert的返回值就是函数处理模板字符串后的返回值,函数会接收到多个参数:

1
2
3
4
5
6
7
8
9
function tag(stringArr, value1, value2){
// ...
}

// 等同于

function tag(stringArr, ...values){
// ...
}

函数的第一个参数是一个数组,数组的成员是模板字符串中没有变量替换的部分,也就是说,变量替换只发生在各个数组成员之间

函数的其他参数,都是模板字符各个变量被替换后的值

回到题目上来

1
highlight`Hello, ${yourName}. I am ${myName}`.

实际上函数调用是:

1
function highlight(['hello, ', '. I am ', ''], yourName, myName) {}

所以可以这样:

1
2
3
const highlight = (strArray, ...rest) => {
return strArray.map((v, key) => v + `<span class="red">${rest[key] || ''}</span>`).join('')
};

另外,有一个String.raw方法,它可以获取一个模板字符串的原始字面量值的

比如:

1
2
3
let name = "Bob";
String.raw `Hi\n${name}!`;
// "Hi\\nBob!",内插表达式还可以正常运行

以后用到的时候再看MDN的文档

参考