关于模板字面量,我有点好奇它的内部结构【玩转前端】
前言
最近翻看源码的时候,发现一些有趣的 JS 的知识点,基于日常的开发经验,我做了一些联想和对比。整个过程充满了乐趣。
于是我想,是不是可以延续这种创意带来的学习的乐趣。
带的富含创造力夜晚的 buff,确实让我拥有了不错的灵感。这些灵感像繁星一样闪耀着我的夜里,留下一行文字:
关于模版字面量,好奇它的内部结构吗?
文章速读
阅读文章,可以有以下收获:
模板字面量的内部结构
编程欢乐小剧场
这天某正在欢乐的敲代码,过程流畅丝滑,不带一丝一毫的停顿。
某再敲下一行代码之后,停了下来,并转身问了一个问题。
某:你认真思考过一个问题吗?
一:我俩为什么相识?不用思考,肯定是考验我的,俗话说,天将降大任于......
某:停,停,嘴皮子太溜了。我是说,你看这行代码。
一:还能写的这么复杂呢?
某:都说模板字面量是一种可执行结构。它的内部结构是什么样的?
一:这个我还真没想过,不过我们可以打印一下。
某:键盘递上
模板字面量的内部结构怎么打印?
我受 MDN 官网的启发,反复试验了几次,我感觉我是弄明白了。跟大家演示一下整个过程。
展开参数
第一种,直截了当的展开参数:
let num1 = 1;
let num2 = 2;
function tag(...strings) {
console.log(strings);
}
tag`string text line ${num1} and line ${num2}`;
打印结果
// > [ [ 'string text line ', ' and line ', '' ], 1, 2 ]
借助关于 String.raw() 的理解,大致明白了这个结构。
这个结构主要包括两个部分:原始字符串和其他字符串。
- 原始字符串会被放在第一个参数中,这个参数类型是数组,而这个参数存在一个特殊的属性 raw ,可以通过它来直接访问模板字符串的原始字符串,而不经过特殊字符的替换。
- 其他字符串参数在原始字符串之后。
需要注意的一点是原始字符串是包含转义字符,而其他字符串包含占位符等,比如代码中的 ${num} 。
转义字符
当模版字符串里面包含像 \n 这类的转义字符,\n 不会被特殊处理,它会被放入原始字符串之中。
tag`string text line ${num1} \n line ${num2}`;
打印结果
// > [ [ 'string text line ', ' \n line ', '' ], 1, 2 ]
raw 属性
raw 属性可以获取一个模板字符串的原始字符串。
let num1 = 1;
let num2 = 2;
function tag(strings) {
console.log(strings.raw);
}
tag`string text line ${num1} and line ${num2}`;
打印结果
// > [ 'string text line ', ' and line ', '' ]
听说模板字面量还支持复杂的写法?
日常开发
在日常开发中,经常在如下的场景中使用模版字面量:
// 三元表达式
type === 'admin' ? `${name}` : `${userName}`;
// 带参数的跳转路径
history.push(`/detail?id=${id}`)
// 简单的求和表达式
var a = 5;
var b = 10;
console.log(`sum: ${a + b}`);
复杂写法
插入循环
下面的代码通过数组循环获取属性 num 的值拼接成字符串,连接左右的字符串'['和']',最终展示为数组的形式。
let example = [{ num: 1 }, { num: 2 }, { num: 3 }];
let str = `数组的另一种展示方式:[${example.map(({ num }) => num).join(', ')}]`;
console.log(str);
打印结果
// > 数组的另一种展示方式:[1, 2, 3]
我从 axios 源码中看到了上面例子中的写法,恍然大悟,模版字面量原来还可以这样玩。
补充模板字面量的知识点
标签函数
前面探索模板字面量的内部结构中的举例,其实还可以将 tag 函数的入参换成下面这种:
let num1 = 1;
let num2 = 2;
function tag(strings, numExp1, numExp2) {
const str0 = strings[0];
const str1 = strings[1];
const str2 = strings[2];
return `${str0}${numExp1}${str1}${numExp2}${str2}`;
}
let output = tag`string text line ${num1} and line ${num2}.`;
console.log(output);
打印结果
// > string text line 1 and line 2.
标签函数的定义
有了前面的基础,标签函数也好理解了:
接受了一个模板字符串作为实参的函数。
标签函数的参数
再回到 tag 函数参数,这三个参数也比较好理解,前面的过模板字面量的内部结构中有过介绍。这里再详细介绍一下:
strings:字符串数组,里面包含模板字符串中全部的原始字符串。
num1:第一个占位符的值。
num2:第二个占位符的值。
标签函数的参数转换
熟悉模板字面量的内部结构的另一个帮助,我们可以继续tag 函数参数的转换实验,上面的代码等同于下面的代码:
let num = 1;
let num2 = 2;
function tag(strings, ...rest) {
const str0 = strings[0];
const str1 = strings[1];
const str2 = strings[2];
const numExp1 = rest[0];
const numExp2 = rest[1];
return `${str0}${numExp1}${str1}${numExp2}${str2}`;
}
let output = tag`string text line ${num} and line ${num2}.`;
console.log(output);
小结
- 模版字面量的内部结构包括原始字符串和其他字符串两个部分。
- 原始字符串中包含转义字符,其他字符串主要包括占位符等。
- 模版字面量自带的 raw 属性可以获取一个模板字符串的原始字符串。
- 模版字面量的复杂写法,某些情况下比较灵活的得到想要的结果。
- 标签参数是指接受一个模板字符串作为实参的函数。
总结
关于模版字面量的内部结构,摸索的过程还是很有趣的。虽然从前面的篇幅中看着很简单,但是其实我反复实验了多次,并且借助 String.raw() 的知识点,才很好的理解了输出中的结果。
虽然事情没有看上去的简单,但是结果还是很令人欣慰的。
今天还有一个不错的收获,原来模版字面量里还可以插入循环,一扇新的窗户打开了。
作者:非职业「传道授业解惑」的开发者叶一一
简介:「趣学前端」、「CSS畅想」系列作者,华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。
- 点赞
- 收藏
- 关注作者
评论(0)