淺析Prototype的模板類 Template

來源:互聯網
上載者:User

用過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是一個Null 物件,那麼我們直接刪除需要替換的部分
比如

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是一個Null 物件,那麼我們直接刪除需要替換的部分
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有一個嵌套調用的情況,不過意思都一樣,最後丟回一個函數就可以了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.