[ 模板解析器 | 青训营笔记]

52 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第三天

记录一下最近遇到的一个需求和对应的解决方法

顺带对更优解进行了衍生拓展

一、需求讲解

需要实现一个“填充渲染”函数,根据传入的对象,对字符串的模板字符串进行填充,如下代码所示:定义一个render()函数,输入为一个对象。

var intro = 'I am ${name}, I am ${age} years old, my daughter is ${children}';
var info = {
  name: 'LiHua',  age: 34,  children: 'Mandy'
};
//...
var result = intro.render(info);
console.log(result);//I am LiHua, I am 34 years old, my daughter is Mandy

二、解决思路

1.遇到上述需求,我们先观察一下render函数的用法,他是intro这个字符串上的一个方法,这时候,因为不确定传来的承载着这个字符串的变量名叫intro还是叫xxx,我们统一把这个方法挂载到String原型链上面。

2.接着,考虑render函数的输出。可以观察到result需要输出为一个字符串,所以intro.render(info)需要输出一个字符串。所以此处最适合需求的render函数的输出是使用模板字符串。

3.接着考虑函数逻辑部分,主要分别讲解以下两种方法

第一种是使用eval()函数,因为题目中需要对调用render函数的字符串(this)进行填充,所以需要在函数内部作用域依据传入对象的属性名创建变量并赋值。此时需要用到模板字符串来动态生成变量名,故可以用eval来接收并解析声明变量的模板字符串语句。

var intro = 'I am ${name}, I am ${age} years old, my daughter is ${children}';
var info = {
  name: 'LiHua',  age: 34,  children: 'Mandy'
};
String.prototype.render = function(obj){
  eval(`var {${Object.keys(obj).join(',')}} = obj`)
    return eval('`' + this + '`')
  }
var result = intro.render(info);
console.log(result);

第二种方法是更为简洁的方法,那就是with()。                                                                  with这个函数在大括号内没有传入对应要修改的对象的时候,会自动依据传入的对象在在全局作用域创建对象。如果大括号有传入,就会修改对应传入对象的属性值。

例如:传入这个对象时,在大括号内没有传入对应要修改的,

var info = {name: 'LiHua',  age: 34,  children: 'Mandy'};

with(info){
    
  }}

所以自动在全局创建了:

var name = 'LiHua'; var age = '34' ; children = 'Mandy'

var intro = 'I am ${name}, I am ${age} years old, my daughter is ${children}';
var info = {
  name: 'LiHua',  age: 34,  children: 'Mandy'};
String.prototype.render = function(obj){
  with(obj){
    return eval('`' + this + '`')
  }}
var result = intro.render(info);
console.log(result);

所以最后this能够获取到全局的name,age和children,就能够填入了