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

スポンサーリンク
スポンサーリンク
ライフスタイル関連のコンテンツ
お金 | 仕事 | 勉強 | プライベート | 健康 |
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般

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。

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

スポンサーリンク
 
スポンサーリンク