如果有这样一种需求
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;
})
完美解决问题