手写一个简单模板引擎总结

如果有这样一种需求

var data = {
    name: 'ruoyu',
    addr: 'Hunger Valley'
};
var tpl = 'Hello, my name is  {{name}}. I am in {{addr}}.';

要求你把tpl字符串里形如{{}}的字符串替换成data对象里面对应的key,我们怎么搞

我们首先分析形如{{}}字符串的规律,然后定义一个正则来匹配它。通过分析,我们知道{{}}里面是一个变量。

那么他就满足变量的一般规则:

1.变量必须以字母、下划线或者$开头,但是不能以数字开头

2.变量第一个符号后面可以接字母、数字、下划线、或者.

我们依照这两条规则来定义一个正则

var reg=/{{[a-zA-Z_$][a-zA-Z0-9_.]*}}/g;

我们可以使用字符串的replace方法来匹配正则,达到字符串替换目的

var newStr = tpl.replace(reg,'123')
console.log(newStr)

浏览器输出结果:

Hello, my name is 123. I am in 123.

这样的替换方式功能太弱,他只能把匹配到的字符串替换成相同的内容,而我们的目的是把{{name}}替换成data[name],把{{addr}}替换成data[addr]。

如果你去看replace()方法的api,就会发现它的第二个参数可以是一个函数。

var newStr = tpl.replace(reg,function(raw,key,offset,string){
})

function的第一个参数raw是正则匹配到的内容{{name}}、{{addr}}

如果把reg写成这样

var reg=/{{([a-zA-Z_$][a-zA-Z0-9_.]*)}}/g;

相比上面,多了一对括号,也就是给reg添加一个子表达式,这样function的第二个参数就起作用了,key的意思是reg的第一个子表达式匹配到的内容name、addr

这样就可以满足目的

var newStr = tpl.replace(reg,function(raw,key,offset,string){
    return data[key]||raw;
})

但是,还有一个问题需要解决,假如data这样写

var data={
    name: 'ruoyu',
    addr: 'Hunger Valley',
    friend: {
        name: 'hunger',
        car: {
            color: 'white'
        }
    }
}
var tpl = 'Hello, my name is  {{name}}. I am in {{age}},I have a friend {{friend.name}},he has a {{friend.car.color}} car'

这样使用上面的规则就匹配不到了,因为data对象里没有名字是friend.name和friend.car.color的key,我们可以巧妙的利用数组的shift()方法来解决这个问题

先把匹配到的data里面不存在的key变成一个数组

var newStr = tpl.replace(reg,function(raw,key,offset,string){
    var paths=key.split('.');
    var lookup=data;
    while(paths.length>0){
        lookup=lookup[paths.shift()];
    }
})

数组的shift()方法的作用是删除并返回数组的第一个元素,假如匹配到的key是friend.car.color,那么paths=['friend','car','color'];paths.length=3>0,进入第一次循环:paths.shift()返回friend,paths=['car','color'],lookup=data[friend]={name:'hunger',car:{color:'white'}}

这样反复进行while循环,直到paths里面什么都没有的时候,这时的lookup就是我们需要的color了。

var newStr = tpl.replace(reg,function(raw,key,offset,string){
    var paths=key.split('.');
    var lookup=data;
    while(paths.length>0){
        lookup=lookup[paths.shift()];
    }
    return lookup||raw;
})

完美解决问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容