短小精悍的Javascript模板引擎

今天看到Jonh Resig的博客里面提到了他在他的Secrets of the JavaScript Ninja这本书里面介绍的一种简单的模板,代码如下:

// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function(){
var cache = {};

this.tmpl = function tmpl(str, data){
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = !/\W/.test(str) ?
cache[str] = cache[str] ||
tmpl(document.getElementById(str).innerHTML) :

// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +

// Introduce the data as local variables using with(){}
"with(obj){p.push('" +

// Convert the template into pure JavaScript
str
.replace(/[\r\t\n]/g, " ")
.split("<%").join("\t") .replace(/((^|%>)[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%>/g, "',$1,'")
.split("\t").join("');")
.split("%>").join("p.push('")
.split("\r").join("\\'")
+ "');}return p.join('');");

// Provide some basic currying to the user
return data ? fn( data ) : fn;
};
})();

这段代码非常简单,但是却有不少trick。而且这些trick十分的优雅(John resig一向擅长写优雅的javascript)。非常值得读一下。思路就是把一段模板引擎里面的求值代码标记出来,将其余代码用单引号包裹起来,所以代码会分为文本和求值两种部分,压入一个Array,最后join。把这个逻辑用string的形式初始化一个Function对象,然后cache起来就成为一个高效的javascript模板引擎了。不过这个引擎只有求值赋值的功能,没有更加复杂的逻辑控制如if, else, for这些循环,但是在求值部分增加一些正则判断来处理这部分逻辑也是可行的。我非常喜欢的Trimpath Javascript Template估计也是这个思路(虽然经常用,但是由于代码可读性的问题一直没有仔细阅读它的源码)。

这段代码里面的闭包用法也很不错,可以防止命名冲突和全局变量的污染,不过这个写法估计大家都比较熟悉了。

模板的用法就不赘述了,如果你想用这个微型模板可以看看John Resig的JavaScript Micro-Templating

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.