视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
浅析Prototype的模板类Template_prototype
2020-11-27 21:01:37 责编:小采
文档


用过Prototype的人都知道,里面有个类叫做Template,用法示例如下:
代码如下:
var str = '#{what} may have gone, but there is a time of #{how}';
var object = {
what : 'Swallows',
how : 'return'
}
var template_1 = new Template(str);
var result = template_1.evaluate(object);

console.log('result:',result);
//输出:'Swallows may have gone, but there is a time of return'

这么挺方便的,所以下面就简单的分析一下实现原理,也算是源码解读的一个笔记。

我们先看一下一般需求里面会用到的一些情况,还是用上面的例子,先决定我们的形式,替换的部分是形如#{what}的内容,其中what是一个object对象的一个关键字。
现在有个问题就是,如果object是一个嵌套的对象,我们该怎么替换?
即:
代码如下:

var object = {
what : {
name : 'Swallows'
},
how : 'return'
}


最开始的#{what}肯定不能满足要求,所以我们硬性规定,如果要实现嵌套对象的替换,写作#{what.name}或者#{what[name]}。

所以最开始的例子可以写作:
代码如下:
输出:'Swallows may have gone, but there is a time of return'


源码里面有个正则var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;就是用来实现这个目的的。依次类推,任何深层次的嵌套都可以实现。

要做替换,我们最核心的就是要有一个替换字符的方法,源码里面用的是gsub,下面给出一个gsub的最简版本:
代码如下:

function gsub(str,pattern, replacement){
var result = '',
source = str,
match;
//下面的每一次匹配都是分成三段来操作的
//相当于 $` $& $'
while(source.length > 0){
match = source.match(pattern);
if(match){
result += source.slice(0, match.index);
result += replacement(match);
source = source.slice(match.index + match[0].length);
}else{
result += source;
source = '';
}
}
return result;
}


这个调用方法和原理跟我前面涉及的replace类似,基本可以互换。http://www.cnblogs.com/xesam/archive/2011/12/05/2276783.html
代码如下:
输出there is a time ofdemo

下面回到Template来,基本要求:有类有方法
代码如下:

var Template = function(template, pattern){
this.template = template.toString();
this.pattern = pattern || Template.Pattern;
};
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype.evaluate = function(object){}


template就是最初例子中的str,pattern是匹配规则,object就是最初例子中的object;现在重点剩下evaluate方法的实现:
直接调用gsub方法,主要是gsub中replacement的方法了。
可能出现的情况,
第一、object是一个空对象,那么我们直接删除需要替换的部分
比如

var str = '#{what} may have gone, but there is a time of #{how}';
var object = {}
那么就直接返回' may have gone, but there is a time of '


第二、转义部分直接保留
代码如下:
var str = '\\#{what} may have gone, but there is a time of \\#{how}';
var object = {
what : 'Swallows',
how : 'return'
}

那么就直接返回'\\#{what} may have gone, but there is a time of \\#{how}';

这些情况在代码中都要处理,具体代码如下
代码如下:
Template.prototype.evaluate = function(object){
//gsub(str,pattern, replacement)
return gsub(this.template,this.pattern,function(match){
var before = match[1];//这里的match[1]就是Template.Pattern中(^|.|\r|\n)匹配的部分
var content = match[2];//这里的match[1]就是Template.Pattern中(#\{(.*?)\})匹配的部分
var expr = match[3];//这里的match[1]就是Template.Pattern中(.*?)匹配的部分
//示例:
//对于 s#{what} 来说before='s',content='#{what}',expr='what'

//第一、object是一个空对象,那么我们直接删除需要替换的部分
if(object == null){
return (match[1] + '');
}
//第二、转义部分直接保留
if (before == '\\'){
return content;
}

//除了上面的两种情况,下面是正常的替换流程。
var ctx = object;

//下面这个正则我在前面说过,是为了匹配嵌套对象的。看最后面的(\.|\[|$)是为了确定有没有嵌套的子对象匹配。
//#{what.name}中的'.'
//或者#{what[name]}中的'['
//也就是下面的match[3]

var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
match = pattern.exec(expr);

while (match != null) {
if(/^\[/.test(match[1])){
var comp = match[2].replace(/\\\\]/g, ']');
}else{
var comp = match[1];
}
ctx = ctx[comp];//如果ctx[comp]是一个字符串,那么下面一步就可以收工了,如果ctx[comp]还是一个对象,那么抱歉,加班继续干吧。

if (null == ctx || '' == match[3]){//需要替换的不是object的嵌套子对象,那么就直接中断循环。替换成功,下班。
break;
}

//下面的仅仅是为了剥离出来关键字,其他操作用在循环里面再来一次。
if('[' == match[3]){
expr = expr.substring(match[1].length)
}else{
expr = expr.substring(match[0].length)
}
match = pattern.exec(expr);
}

return before + ctx;
});
};

当然,源码中并没有这么简单,还参杂了一写检测和判断,比如替换str的非法字符,处理replacement为字符串的情况等等。具体可以去查看源码。
可能有些复杂的就是处理replacement为字符串的情况,gsub和Template有一个嵌套调用的情况,不过意思都一样,最后丢回一个函数就可以了。

下载本文
显示全文
专题