当我浏览How JavaScript Micro-Templating源代码时,我对2个问题感到困惑:
代码:
(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;
};
})();
"<div>",name,"</div>"
之类的声明,然后我们可以使用声明。但是String.replace()总是返回字符串。我们期望一个符号而不是一个字符串。所以在这种情况下,evel类型是最佳选择。这就是我得到的。如果我错了,请纠正我。示例:
function wrapperFn(data) {
var fn = function anonymous(obj) {
var p=[],
print=function(){p.push.apply(p,arguments);};
with(obj) {
p.push(' <p>',name,'</p> ');
}
console.log("p.join(''):", p.join(''));
return p.join('');
}
return fn(data);
}
答案 0 :(得分:0)
为什么要使用新函数而不是定义一个通用函数?
因为它需要eval
模板中的代码。通过这种花哨的替换,它将模板语言转换为有效的JS语句。那些(仍然是字符串)然后通过new Function
成为一个函数体。例如,user_tmpl
示例将变为
function(obj) {
var p=[],
print=function(){p.push.apply(p,arguments);};
with(obj) {
p.push(' ');
for ( var i = 0; i < users.length; i++ ) {
p.push(' <li><a href="',users[i].url,'">',users[i].name,'</a></li> ');
}
p.push('');
}
return p.join('');
}
为什么在新函数中没有直接引用数据参数,但可以用正确的值替换。我希望使用数据[$ 1]从数据中获取正确的值。
因为data
参数(如果存在)作为obj
参数传递给新的fn
函数,所以在return子句(最后一行代码)中。然后,您可以访问由with
statement引起的变量的属性(users
)。如果未传递数据,则将返回新创建的函数,而不是
var res = tmpl("templname", data);
您也可以使用
var tmplFn = tmpl("templname");
var res = templFn(data);
这个概念被称为partial application,这里被错误地称为“currying”(一个类似但非常不同的概念)。