# 1.概览

模板字符串是允许嵌入表达式的字符串。您可以使用多行字符串、字符串插值和表达式插值功能。在 ES2015 规范的早期版本中,它们被称为“模板字符串”。

;`\`` === '`' // true
;`\${1}` === '${1}' // true
1
2

在下面这个例子中,字符串连接有两个令我印象深刻的恼人特性。用反斜杠转义撇号,并试图用双引号和单引号弄清楚字符串末尾发生了什么。模板文字减轻了这两个问题,我们留下了更清晰的代码行。

const p = {
  name: 'Jackson',
  nn: 'Jak',
}
// STRING CONCATENATION
console.log("Hi, I'm " + p.name + '! Call me "' + p.nn + '".')
// TEMPLATE LITERALS
console.log(`Hi, I'm ${p.name}! Call me "${p.nn}".`)
// "Hi, I'm Jackson! Call me 'Jak'."
1
2
3
4
5
6
7
8
9

ES5

const a = 5
const b = 10
console.log('Fifteen is ' + (a + b) + ' and\nnot ' + (2 * a + b) + '.')
// "Fifteen is 15 and
// not 20."
1
2
3
4
5

ES6

const a = 5
const b = 10
console.log(`Fifteen is ${a + b} and
not ${2 * a + b}.`)
// "Fifteen is 15 and
// not 20."
1
2
3
4
5
6

如您所见,在使用模板文字时,我们的代码更易于阅读。您可以轻松查看我们的字符串在说什么以及变量插入的位置。

对于换行符来说,我们可以看下面这个例子:

// STRING CONCATENATION
console.log('Dear Mom,\n' + 'Hope you are well.\n' + '\tLove, your son')
// TEMPLATE LITERALS
console.log(`Dear Mom,
Hope you are well.
    Love, your son`)
// Dear Mom,
// Hope you are well.
//     Love, your son
1
2
3
4
5
6
7
8
9

使用模板字符串,插入任何新行字符、制表符、空格等都将成为字符串的一部分。这既是福也是祸,但就易读性而言绝对是一个优势。

不过,在 JavaScript 术语中,模板字符串是一种连接字符串的方法,同时允许嵌入表达式并提高易读性。

const person = 'Mike'
const age = 28

function myTag(strings, personExp, ageExp) {
  const str0 = strings[0] // "That "
  const str1 = strings[1] // " is a "
  const str2 = strings[2] // "."

  const ageStr = ageExp > 99 ? 'centenarian' : 'youngster'

  // We can even return a string built using a template literal
  return `${str0}${personExp}${str1}${ageStr}${str2}`
}

const output = myTag`That ${person} is a ${age}.`

console.log(output)
// That Mike is a youngster.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 模板字符串的特点:

  • 用反引号(`)标识。
  • 如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
  • 模板字符串中嵌入变量,需要将变量名写在${}之中。一些运算也能嵌入其中。
  • 模板字符串甚至还能嵌套。

# 2.标签模板

模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。

function tagFunc(...args) {
  return args
}

const setting = 'dark mode'
const value = true
console.log(
  tagFunc`Setting ${setting} is ${value}!`, //[['Setting ', ' is ', '!'], 'dark mode', true]
  [['Setting ', ' is ', '!'], 'dark mode', true]
) //[['Setting ', ' is ', '!'], 'dark mode', true]
1
2
3
4
5
6
7
8
9
10

第一个反引号之前的函数 tagFunc 称为标签函数。它的参数是:

  • 模板字符串(第一个参数):一个数组,文本片段围绕插值${}。 在示例中:['Setting ',' is ', '!']
  • 替换(剩余参数):插值。 在示例中:dark modetrue

字符串的静态(固定)部分(模板字符串)与动态部分(替换)保持分离。

# hello world

function tag(...e) {
  console.log(e) // [['hello world']]
}
tag`hello world`
1
2
3
4

从 hello world 中不难看出,标签模板中的字符串参数会被放在数组内。我们现在看下加入插值后会发生什么变化。

# 加入插值${}

function tag(...e) {
  console.log(e) // [['hello world ', ""], '123']
}
const a = '123'
tag`hello world ${a}`
1
2
3
4
5

其实 tag 相当于传入tag(['hello world ', ""], '123')

function tag(...e) {
  console.log(e) // [['hello world ', ""], '123']
}
const a = '123'
tag`hello world ${a}`

tag(['hello world ', ''], '123') // [['hello world ', ""], '123']
1
2
3
4
5
6
7

# 拼合

let total = 30
let msg = passthru`The total is ${total} (${total * 1.05} with tax)`

function passthru(literals) {
  let result = ''
  let i = 0

  while (i < literals.length) {
    result += literals[i++]
    if (i < arguments.length) {
      result += arguments[i]
    }
  }

  return result
}

console.log(msg) // "The total is 30 (31.5 with tax)"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Last Updated: 3/28/2024, 5:23:17 PM