JavaScriptのテンプレートエンジンの仕組みを解読してみる

はてなブックマークに追加はてなブックマーク Yahoo!ブックマークに登録 ニフティクリップに追加 Livedoor クリップに追加 BuzzurlにブックマークBuzzurlにブックマーク Twitterに投稿  

Latest topics > PHPとかerbのようなテンプレートをJavaScriptで。 - outsider reflex という記事を見つけて、JavaScriptでのテンプレートエンジンのコードが書いてあった。
パッと見で理解できないので、1行づつ順を追って解読を試みてみたメモです。

function parseTemplate(aCode, aContext) {
  var __parseTemplate__codes = [];
  aCode.split('%>').forEach(function(aPart) {
    var strPart, codePart;
    [strPart, codePart] = aPart.split('<%');
    __parseTemplate__codes.push('__parseTemplate__results.push('+
                                strPart.toSource()+
                                ');');
    if (!codePart) return;
    if (codePart.charAt(0) == '=') {
      __parseTemplate__codes.push('__parseTemplate__results.push(('+
                                  codePart.substring(1)+
                                  ') || "");');
    }
    else {
      __parseTemplate__codes.push(codePart);
    }
  });
  var __parseTemplate__results = [];
  with(aContext|| {}) {
    eval('(function() { '+__parseTemplate__codes.join('\n')+' }).call(aContext|| {})');
  }
  return __parseTemplate__results.join('');
}
 
var source = <![CDATA[
      大切な事なので3回言います。
      <% for (var i = 0; i < 3; i++) { %>
        今日は<%= today %>です。
      <% } %>
      オーケー?
    ]]>.toString();
var params = {
      today : (new Date()).toString()
    };
var result = parseTemplate(source, params);


まずは、テンプレート部分のソースのみ抜き出す。

大切な事なので3回言います。
<% for (var i = 0; i < 3; i++) { %>
今日は<%= today %>です。
<% } %>
オーケー?

以下、少しずつ解読して行きました。


1.aCode.split('%>') により・・・

①大切な事なので3回言います。\n<% for (var i = 0; i < 3; i++) {
②\n今日は<%= today
③です。\n<% }
④\nオーケー?

に分割される。


2.forEachの中で、[strPart, codePart] = aPart.split('<%'); により

strPart            codePart
① "大切な事…\n"    " for (var i = 0; i < 3; i++) { "
② "今日は"        "= today "
③ "です。\n"        " }"
④ "\nオーケー?"    ""

に分割される。


3.forEachで回し、__parseTemplate__codesを組み立てる。

__parseTemplate__codes には・・・
①'__parseTemplate__results.push(' + strPart.toSource() + ');' という文字列がpushされる。
②codePartに"="(変数での置き換え)が含まれる場合、
'__parseTemplate__results.push((' + codePart.substring(1) + ') || "");' という文字列がpushされる。
③含まれない場合、codePartの文字列がそのままpushされる。


4.strPart, codePart の中身は、

 strPart            codePart
① "大切な事…\n"    " for (var i = 0; i < 3; i++) { "
② "今日は"        "= today "
③ "です。\n"        " }"
④ "\nオーケー?"    ""
であるから、_parseTemplate__codes の配列構造は・・・
_parseTemplate__codes = [
    '__parseTemplate__results.push("大切な事…\n");',
    ' for (var i = 0; i < 3; i++) { ',    // ①
    '__parseTemplate__results.push("今日は");',
    '__parseTemplate__results.push(today);',    // ②
    '__parseTemplate__results.push("です。\n");',
    ' }',    // ③
    '__parseTemplate__results.push("\nオーケー?");',
    ''    // ④
]

という配列が作られる。


5.文字列を組み立てて、evalされる。

__parseTemplate__codes.join('\n') により、

__parseTemplate__results.push("大切な事なので3回言います。\n");
 for (var i = 0; i < 3; i++) { 
    __parseTemplate__results.push("今日は");
    __parseTemplate__results.push(today);
    __parseTemplate__results.push("です。\n");
 }
__parseTemplate__results.push("\nオーケー?");

という文字列が作成され、これがevalされる。
evalは、with(aContext|| {}) により、与えられたコンテキスト(オブジェクト)の中で行われる。(todayは、params.todayとして評価される。)


6.__parseTemplate__results は・・・

["今日は", today(を評価した内容), "です。\n",
 "今日は", today(を評価した内容), "です。\n",
 "今日は", today(を評価した内容), "です。\n",]

という配列構造となる。
これをjoin('')でつないでreturn。


以上、テンプレートエンジンがどんな仕組みで動くのかを知ることが出来ました。
実際に動くかどうかも試してみる。


日時: 2009年05月29日 15:34
コメントを投稿






トラックバック

■この記事のトラックバックURL:
http://www.mapee.jp/mpe334/mt-tb.cgi/478

この記事にトラックバックされる方は、参照先が分かるようにするために、「JavaScriptのテンプレートエンジンの仕組みを解読してみる」へのリンクをお願いいたします。
以下のHTMLタグをトラックバック送信元ページ内に挿入して下さい。



※この記事へのリンクがない、また関連のないページからのトラックバックは反映されませんので、ご了承下さい。






あわせて読みたいブログパーツ
フィードメーター - ウェブライフハック