浅析Prototype的模板类 Template


Posted in Javascript onDecember 07, 2011

用过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是一个嵌套的对象,我们该怎么替换?
即:

<script type="text/javascript"> 
var object = { 
what : { 
name : 'Swallows' 
}, 
how : 'return' 
} 
</script>

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

所以最开始的例子可以写作:

<script type="text/javascript"> 
var str = '#{what.name} may have gone, but there is a time of #{how}'; 
//或者str = '#{what[name]} may have gone, but there is a time of #{how}'; 
var object = { 
what : { 
name : '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' 
</script>

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

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

<script type="text/javascript"> 
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; 
} 
</script>

这个调用方法和原理跟我前面涉及的replace类似,基本可以互换。http://www.cnblogs.com/xesam/archive/2011/12/05/2276783.html
<script type="text/javascript"> 
console.log(gsub('there is a time of #{how}',/(^|.|\r|\n)(#\{(.*?)\})/,function{ 
return 'demo'; 
})) 
//输出there is a time ofdemo 
</script>

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

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

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有一个嵌套调用的情况,不过意思都一样,最后丢回一个函数就可以了。
Javascript 相关文章推荐
js判断元素是否隐藏的方法
Jun 09 Javascript
jQuery焦点图切换简易插件制作过程全纪录
Aug 27 Javascript
JavaScript导出Excel实例详解
Nov 25 Javascript
Jquery弹出层插件ThickBox的使用方法
Dec 09 Javascript
javascript实现选中复选框后相关输入框变灰不可用的方法
Aug 11 Javascript
JavaScript的模块化开发框架Sea.js上手指南
May 12 Javascript
jQuery layui常用方法介绍
Jul 25 Javascript
JavaScript严格模式下关于this的几种指向详解
Jul 12 Javascript
微信小程序滑动选择器的实现代码
Aug 10 Javascript
修改vue+webpack run build的路径方法
Sep 01 Javascript
layer.js open 隐藏滚动条的例子
Sep 05 Javascript
vue 取出v-for循环中的index值实例
Nov 09 Javascript
js 幻灯片的实现
Dec 06 #Javascript
字符串的replace方法应用浅析
Dec 06 #Javascript
js滚动条回到顶部的代码
Dec 06 #Javascript
javascript检测浏览器flash版本的实现代码
Dec 06 #Javascript
javascript 随机展示头像实现代码
Dec 06 #Javascript
jQuery中需要注意的细节问题小结
Dec 06 #Javascript
jQuery load方法用法集锦
Dec 06 #Javascript
You might like
两种php调用Java对象的方法
2006/10/09 PHP
php中ob(Output Buffer 输出缓冲)函数使用方法
2007/07/21 PHP
PHP 代码规范小结
2012/03/08 PHP
基于PHP文件操作的详解
2013/06/05 PHP
PHP写的加密函数,支持私人密钥(详细介绍)
2013/06/09 PHP
thinkphp3.x中display方法及show方法的用法实例
2016/05/19 PHP
PHP面向对象程序设计组合模式与装饰模式详解
2016/12/02 PHP
PHP7 echo和print语句实例用法
2019/02/15 PHP
PHP中16个高危函数整理
2019/09/19 PHP
jQuery判断元素是否是隐藏的代码
2011/04/24 Javascript
xml转json的js代码
2012/08/28 Javascript
JS获取Table中td值的方法
2015/03/19 Javascript
.NET微信公众号开发之创建自定义菜单
2015/07/16 Javascript
javascript常用函数(2)
2015/11/05 Javascript
Javascript实现图片轮播效果(二)图片序列节点的控制实现
2016/02/17 Javascript
基于javascript实现页面加载loading效果
2020/09/15 Javascript
AngularJS通过$http和服务器通信详解
2016/09/21 Javascript
angular2中router路由跳转navigate的使用与刷新页面问题详解
2017/05/07 Javascript
Promise扫盲贴
2019/06/24 Javascript
详解Python中__str__和__repr__方法的区别
2015/04/17 Python
如何在Python中编写并发程序
2016/02/27 Python
windows及linux环境下永久修改pip镜像源的方法
2016/11/28 Python
python字符串中的单双引
2017/02/16 Python
python执行精确的小数计算方法
2019/01/21 Python
selenium+python自动化测试之使用webdriver操作浏览器的方法
2019/01/23 Python
python3 json数据格式的转换(dumps/loads的使用、dict to str/str to dict、json字符串/字典的相互转换)
2019/04/01 Python
Python中字符串String的基本内置函数与过滤字符模块函数的基本用法
2019/05/27 Python
Django中的FBV和CBV用法详解
2019/09/15 Python
关于初始种子自动选取的区域生长实例(python+opencv)
2020/01/16 Python
python中openpyxl和xlsxwriter对Excel的操作方法
2021/03/01 Python
什么是事务?事务有哪些性质?
2012/03/11 面试题
C#基础面试题
2016/10/17 面试题
2015年“公民道德宣传日”活动方案
2015/05/06 职场文书
物业保洁员管理制度
2015/08/05 职场文书
严以律己专题学习研讨会发言材料
2015/11/09 职场文书
AJAX学习笔记
2021/05/18 Javascript