进入主题之前先介绍一种创建函数的新方法:new Function()
我们来创建一个函数,名字为foo
function foo(a, b){
return a + b;
}
这种方式是我们普遍使用的,但同样的,我们还可以使用JS语言内置的Function对象来创建这个函数
var foo = new Function('a', 'b', 'return a + b;');
其实这两种写法在JS引擎看来是同一种,因为第一种会被转换为第二种,只不过第一种可读性更好而已。
例子说完了,来看下API:
/**
* 函数名称为 funName
* @param {String} p1 第一个参数名称
* @param {String} p2 第二个参数名称
* ...
* @param {String} body 函数体
*/
var funName = new Function(p1, p2, ..., pn, body);
需要注意的是,p1 到 pn 是参数名称的列表,但 p1 不仅能代表一个参数,也可以是一个逗号隔开的参数列表,所以下面的定义是等价的:
new Function('a', 'b', 'c', 'return a + b + c;');
new Function('a, b', 'c', 'return a + b + c;');
new Function('a, b, c', 'return a + b + c;');
现在进入正题,我在John Resig的博客里发现了这个函数:
// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function(){
var cache = {};
this.tmpl = function tmpl(str, data){
// 查找非单词字符,如<>,没找到表示是ID,找到了表示是模板文本
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;
};
})();
核心是中间那个函数的逻辑,这里我写一个简单的模板:
var str = '<div class="<%=clsName%>">' +
'<h1><%=title%></h1>' +
'<p><%=content%></p>' +
'</div>';
var result = tmpl(str);
console.log(result);
结果为:
function anonymous(obj) {
var p = [], print = function(){ p.push.apply(p, arguments); };
with(obj){
p.push('<div class="', clsName, '"><h1>', title, '</h1><p>', content, '</p></div>');
}
return p.join('');
}
到此, 相信大家都知道这个函数做了什么事了。
作者最后分享了一个查找替换的小技巧,通常我们会用str.replace(/match/g, 'replace'),但是性能上还有一种更好的:
str.split('match').join('replace');