Skip to content

15. 标签函数与模板字符串

观察下面代码,你觉得会输出什么?

js
function test(x) {
  console.log(x)
}

test `hello`
1
2
3
4
5

事实是,这里会打印出一个数组 ['hello']。没错,模板字符串还支持在前面添加一个函数标签,这个函数标签就是一个函数的函数名。

TIP

MDN: 如果一个模板字符串由表达式开头,则该字符串被称为带标签的模板字符串,该表达式通常是一个函数,它会在模板字符串处理后被调用,在输出最终结果前,你都可以通过该函数来对模板字符串进行操作处理。

定义

标签函数:模板字符串在 JS 底层中会被一个默认函数处理,也就是把接收的字符串和参数拼接起来。我们可以自定义该函数,在模板字符串前面添加一个函数标签(函数名),覆盖 JS 默认的函数处理,就能够手动处理模板字符串了

js
tagFunction `string text ${expression} string text`
1

参数获取

模板字符串中的字符和插入的 ${} 中的参数都可以在 arguments 中获取或者定义形参获取。

示例1:使用 arguments 获取

js
let user = {
  name: 'Murphy',
  age: 20
}

function greet() {
  console.log(arguments[0])
  // ["I'm ", ". I'm ", " years old."]
  console.log(arguments[1])
  // Murphy
  console.log(arguments[2])
  // 20
}

greet `I'm ${user.name}. I'm ${user.age} years old.`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

示例2:使用标签函数的形参获取

js
let user = {
  name: 'Murphy',
  age: 20
}

function greet(strs, name, age) {
  console.log(strs[0] + name + strs[1] + age + strs[[2]])
  // I'm Murphy. I'm 20 years old.
}

greet`I'm ${user.name}. I'm ${user.age} years old.`
1
2
3
4
5
6
7
8
9
10
11

结合柯里化:标签函数返回标签函数

js
const tagFunc = (...arg1) => (...arg2) => (...arg3) => arg1 + arg2 + arg3

let res = tagFunc `hello` `world` `123`

console.log(res) // helloworld123
1
2
3
4
5

解释:tagFunc 接收一个模板字符串参数,仍然返回一个标签函数,就可以继续接收模板字符串参数,所以可以连续接收三个模板字符串。

标签函数的应用场景

问题来了,讲了这么多,标签函数有啥用?

React 的 styled-components 就是利用标签函数给 UI 设置样式的:styled-components

js
const Button = styled.a`
  ${props => props.primary && css`
    background: white;
    color: black;
  `}
`
1
2
3
4
5
6