哈喽,大家好,我是Fine。
今天为大家推荐的这篇文章主要介绍正则表达式实现 JS 模板编译的相关内容。包括模板编译的核心流程、正则表达式的基础知识和用途,以 Vue 和 React 为例解释模板编译原理,阐述使用正则表达式实现模板编译的优点、实现方式(基础、优化、递归)及性能优化建议
以下是正文:
面试官问:下面这段代码怎么实现页面渲染?
let str = '我是{{name}},年龄{{age}},性别{{sex}}'
let person = {
name: '张三',
age: 18,
sex: '男'
}你:这不简单吗?用
replace
替换,配合正则表达式匹配模板字符串中的占位符就行了。问:那你能用函数
compile
来实现一下吗?
正文开始~~~
在深入模板编译之前,我们先回顾一下正则表达式的基础知识,因为它是实现模板编译的核心工具之一。
正则表达式(Regular Expressions)是一种强大的文本处理工具,可以用来匹配、查找和替换字符串中的特定模式。下面解释正则主要语法:
\d
:匹配一个数字(0-9)。\d+
:匹配一个或多个数字。/\d+/g
可以匹配字符串中的所有数字。\w
:匹配一个字母、数字或下划线([A-Za-z0-9_]
)。\w+
:匹配一个或多个字母、数字或下划线。/\w+/g
可以匹配字符串中的所有单词。\s
:匹配一个空白字符(空格、制表符、换行等)。\s+
:匹配一个或多个空白字符。/\s+/g
可以匹配字符串中的所有空白。^
:匹配字符串的开头。$
:匹配字符串的结尾。/^Hello/
匹配以 Hello
开头的字符串。\b
:匹配单词的边界(单词的开头或结尾)。/\bcat\b/
匹配独立的单词 cat
,而不会匹配 category
中的 cat
。{n}
:匹配前面的字符恰好 n
次。/\d{3}/
匹配连续的 3 个数字。{n,m}
:匹配前面的字符至少 n
次,最多 m
次。/\d{2,4}/
匹配 2 到 4 个连续数字。*
:匹配前面的字符零次或多次。/a*/
可以匹配 ""
(空)、"a"
、"aa"
等。+
:匹配前面的字符一次或多次。/a+/
可以匹配 "a"
、"aa"
,但不能匹配 ""
。?
:匹配前面的字符零次或一次。/a?/
可以匹配 ""
或 "a"
。[abc]
:匹配 a
、b
或 c
中的任意一个字符。/[aeiou]/g
匹配字符串中的所有元音字母。[a-z]
:匹配任意小写字母。[A-Z]
:匹配任意大写字母。[0-9]
:匹配任意数字。/[a-zA-Z]/g
匹配所有字母(大小写均可)。[^abc]
:匹配除了 a
、b
、c
之外的任意字符。/[^0-9]/g
匹配所有非数字字符。(abc)
:将 abc
作为一个分组。/(\d{2})-(\d{2})/
可以匹配 12-34
,并捕获 12
和 34
。(?:abc)
:分组但不捕获。/(?:\d{2})-(\d{2})/
匹配 12-34
,但只捕获 34
。/a.*b/
匹配 "aabab"
中的 "aabab"
。?
,表示尽可能少地匹配字符。/a.*?b/
匹配 "aabab"
中的 "aab"
。匹配 URL:
/^(https?://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-]*)*/?$/
匹配手机号(中国大陆) :
/^1[3-9]\d{9}$/
匹配日期(YYYY-MM-DD) :
/^\d{4}-\d{2}-\d{2}$/
从上面可以看出正则用途很多,包括:
在前端开发中,模板编译允许我们将模板字符串(如 {{name}}
)转换为实际的 HTML 内容,并根据数据动态更新视图。下面我们以 Vue.js 和 React 为例,简单解释模板编译的实现原理。
Vue.js 使用模板引擎来实现数据绑定和视图更新。它的模板语法非常直观,允许开发者在 HTML 中直接嵌入 JavaScript 表达式和指令。例如:
<div id="app">
{{ message }}
</div>
在这个例子中,{{ message }}
是一个插值表达式,Vue 的模板编译器会将其转换为渲染函数。渲染函数在运行时根据数据的变化动态更新 DOM。
React 虽然没有内置的模板引擎,但它使用 JSX(JavaScript XML)来描述 UI。JSX 看起来很像 HTML,但实际上它是 JavaScript 的一种扩展语法。例如:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
在这个例子中,<h1>Hello, {props.name}</h1>
是一个 JSX 表达式,它会被 Babel 等工具编译为 React.createElement
函数调用。React 的虚拟 DOM 机制会根据这些函数调用生成实际的 DOM 节点,并在数据变化时高效地更新 DOM。
它允许我们将模板字符串(如
{{name}}
)转换为实际的 HTML 内容,并根据数据动态更新视图。使用正则表达式实现模板编译有以下几个优点:
灵活性:正则表达式可以灵活地匹配各种复杂的模式,适合处理模板字符串中的占位符。 高效性:正则表达式的匹配和替换操作非常高效,适合处理大量的模板字符串。 简洁性:使用正则表达式可以大大简化代码,减少重复的逻辑。
接下来,我们通过一个简单的例子,使用正则表达式实现模板编译。
<script>
let str = '我是{{name}},年龄{{age}},性别{{sex}}';
let person = {
name: '张三',
age: 18,
sex: '男'
};
function compile(template, data) {
let reg = /{{(\w+)}}/;
while (reg.test(template)) {
let key = reg.exec(template)[1]; // 捕获占位符中的内容
let value = data[key]; // 从数据中获取对应的值
template = template.replace(reg, value); // 替换占位符
}
return template;
}
console.log(compile(str, person)); // 输出:我是张三,年龄18,性别男
</script>
思路解析
/{{(\w+)}}/g
匹配模板中的占位符,如 {{name}}
。(\w+)
捕获 {{}}
中的内容(如 name
)。reg.exec(template)
返回数组,[0]
是完整匹配(如 {{name}}
),[1]
是捕获内容(如 name
)。let arr = reg.exec(template)[1];
提取变量名,从数据中获取对应值。template.replace(reg, value)
替换占位符为实际值。这时候你为了炫技,又写出其他表达形式
function compile(template,data) {
let reg = /\{\{([a-z]+)\}\}/g
// 方式一:使用展开运算符
return template.replace(reg,(...args)=>{
return data[args[1]]
})
// 方式二:直接传并且判断path是否还需要替换
return template.replace(reg,(match,path) => {
console.log(match,path);
return path in data ? data[path] : ''
})
}
这里发一下match,path对应内容,大家应该更好理解:
为了确保模板中的所有占位符都被替换,我们可以使用递归:
<script>
function compile(template, data) {
let reg = /{{(\w+)}}/;
if (reg.test(template)) {
let key = reg.exec(template)[1];
let value = data[key] || '';
template = template.replace(reg, value);
return compile(template, data); // 递归调用
} else {
return template;
}
}
console.log(compile(str, person)); // 输出:我是张三,年龄18,性别男
</script>
我们也看看正则表达式对象执行几次:
在实际项目中,模板编译的性能非常重要。给出一些优化建议:
g
标志)一次性匹配所有占位符。本文转自 https://juejin.cn/post/7457521695621873679
如有侵权,请联系删除。
还没有使用过我们刷题网站(https://fe.ecool.fun/)或者刷题小程序的同学,如果近期准备或者正在找工作,千万不要错过,题库主打题全和更新快哦~。
有会员购买、辅导咨询的小伙伴,可以通过下面的二维码,联系我们的小助手。