JavaScript Micro-Templating如何工作?

时间:2013-04-18 11:02:44

标签: javascript

当我浏览How JavaScript Micro-Templating源代码时,我对2个问题感到困惑:

  1. 为什么要使用 new Function 而不是定义一个通用函数?
  2. 为什么在 new Function 中没有直接引用 data 参数,但可以替换为正确的值。我希望使用 data [$ 1] 从数据中获取正确的值。
  3. 代码:

    (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;
      };
    })();
    
    1. 期望获得"<div>",name,"</div>"之类的声明,然后我们可以使用声明。但是String.replace()总是返回字符串。我们期望一个符号而不是一个字符串。所以在这种情况下,evel类型是最佳选择。这就是我得到的。如果我错了,请纠正我。
    2. 第二个问题的关键:
      • currying功能
      • with statement
    3. 示例:

      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);
      
      }
      

1 个答案:

答案 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”(一个类似但非常不同的概念)。