Hello,大家好,我是 Sunday。
这个问题具体是这样的:请为字符串增加一个 render 方法,可以实现如下最终的打印。
const template = '我是 ${name}, 年龄 ${age} 岁'const employee = { name: 'Sunday', age: 18}const renderStr = template.render(employee)// 输出成字符串console.log(renderStr) // '我是 Sunday, 年龄 18 岁'
乍一看,这不就是 模板引擎 吗?合着这是让我手写一个 `` 的简易版出来啊。
不过还好,既然是简易版那就并不复杂。一共有三种方式,咱们来看看吧!
使用正则表达式应该是大多数的同学第一时间想到的方案了。
只需要通过正则替换 ${name} 和 ${age} 就可以直接实现对应的功能。
String.prototype.render = function (obj) { const template = this const variableRegex = //$/{([^${}]+)/}/g template.replace(variableRegex, ($0, variable) => { // 打印对应的属性 console.log(variable) })}const template = '我是 ${name}, 年龄 ${age} 岁'template.render()
通过以上代码我们可以直接拿到 ${name} 之中的属性,所以接下来咱们就只需要完成替换即可。
// 为 String 对象的原型添加一个名为 render 的方法String.prototype.render = function (obj) { // 保存调用该方法的字符串实例 const template = this; // 定义一个正则表达式,用于匹配 ${variableName} 格式的变量 const variableRegex = //$/{([^${}]+)/}/g; // 定义一个函数,用于根据传入的对象获取变量的值 const getVariableValue = (variable) => { // 将变量名按照 '.' 分隔成数组,例如 'user.name' 会分隔成 ['user', 'name'] variable = variable.split('.'); // 初始化 variableValue,使其指向传入的对象 obj let variableValue = obj; // 遍历分隔后的变量名数组,逐层获取嵌套属性的值 while (variable.length) { // 取出数组的第一个元素,并获取对应的属性值 variableValue = variableValue[variable.shift()]; } // 返回最终获取到的变量值 return variableValue; }; // 使用 replace 方法替换模板字符串中的变量 // $0 是匹配到的整个字符串,例如 ${name} // variable 是捕获组中的变量名,例如 name const renderStr = template.replace(variableRegex, ($0, variable) => { // 获取变量值并替换模板中的变量 return getVariableValue(variable); }); // 返回替换后的字符串 return renderStr;};
eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
比如:
const employee = { name: 'Sunday', age: 18}const { name } = employeeconsole.log(name) // Sunday
这样的代码使用 eval 方法可以这么写:
const employee = { name: 'Sunday', age: 18}// 注意:必须是 vareval('var { name } = employee')console.log(name) // Sunday
这样的好处在于 可以根据 obj 的 key 动态的生成新的变量。
因此,就可以得到如下代码:
// 为 String 对象的原型添加一个名为 render 的方法String.prototype.render = function (obj) { // 保存调用该方法的字符串实例 const template = this; // 使用 eval 动态解构 obj 对象,将其属性名作为变量名,并赋值给这些变量 // 例如,obj = { name: 'Sunday', age: 18} // 生成的代码类似于:var { name, age, job } = obj; eval(`var {${Object.keys(obj).join(',')}} = obj`); // 使用模板字符串替换变量,并生成最终的字符串 // 这里的 eval 用于解析和执行模板字符串,其中包含 obj 对象的属性值 // 例如,template = '我是 ${name}, 年龄 ${age} 岁' // 生成的代码类似于:`我是 ${name}, 年龄 ${age} 岁` const renderStr = eval('`' + template + '`'); // 返回替换后的字符串 return renderStr;}
with 语句扩展一个语句的作用域链
with 关键字属于被弃用的语法(但是 Vue3 的源码中依然使用到了 with),但是在这里依然可以实现对应的功能。
图片
我们可以通过以下示例来演示 with 的作用:
const employee = { name: 'Sunday', age: 18}with (employee) { console.log(name, age) // Sunday 18}
基于这个特性,使用 with 实现这个功能就非常简单了。
String.prototype.render = function (obj) { with(obj) { // this 实例。即:我是 ${name}, 年龄 ${age} 岁 // 两边加上 ` ` 即可利用 ES6 的模板运算符实现此功能 return eval('`' + this + '`') }}
本文链接:http://www.28at.com/showinfo-26-91363-0.html面试官:你能实现一个 JavaScript 模板引擎吗?
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 记一次 .NET某工控WPF程序被人恶搞的卡死分析
下一篇: Python 对象的行为是怎么区分的?