プリミティブクラスの拡張

CouchDBのスレでテンプレートエンジンの話があがっていたので、首を突っ込んでみた。いろいろあるんだがEJSをおすすめしたら、<%= %> がデフォでHTMLエスケープされないのが気に入らん、だそうで。Railsはじめたときに、確かに気に入らなかったんだが、もう慣れちゃったよ、と思っていたら、RailsでもデフォルトでHTMLエスケープされるようになった、ということを別の人から教えてもらった。

ちなみに、MLの議論のほうは、wikiにまとめられています。

http://wiki.apache.org/couchdb/Generating%20HTML%20from%20Javascript%20shows%20and%20lists

mustache.js はRubyの実装の移植版ですね、おすすめらしい。

それはともかく、もうEJSで作っちゃったコードがたくさんあるので、今後もEJSを使うんだろう。
ということで、EJSをハックしにかかって、Railsと同じように <%= foo %> <%= foo.htmlSafe() %> と書けるようにした。


それはともかく、prototype拡張でよく分からないことがある。htmlSafe() を文字列で透過的に呼べるようにStringを拡張した。拡張の危険性は分かっているつもりだが。

String.prototype.htmlSafe = function(){
   this._html_safe = true;
   return this;
}
String.prototype.isHtmlSafe = function(){
   return this._html_safe == true; 
}

でもって、次のプログラムを実行する。結果は分かりやすいように、 // -> で書いた。print = console.log と書いているのはRhinoSpiderMonkeyFirebug のコンソールの3つで確認するため。

print = console.log;
var a = new String("a");
var b = "a";
print(typeof a);  // -> object
print(typeof b);  // -> string
a.htmlSafe();
b.htmlSafe();
print(a.isHtmlSafe());  // -> true
print(b.isHtmlSafe());  // -> false

tyepof が違うのはまぁよしとしよう。参照型と値型。 で、b.htmlSafe() が自身を書き換えない点に注意をしたい。というか、ここまで書いた時点で、値型でメソッド呼び出しができるの辺りに疑問を持った。

var b = "a";
String.prototype.htmlSafe = function(){
   this._html_safe = true;
   print(this === b); // -> false
   return this;
}
b.htmlSafe();

ええっと、これ、暗黙でStringオブジェクトにしているってこと?となると、"" のような値型とStringのような参照型でオートボクシングしているってこと?

なにこの〜と思って、apply でも確認する。

print = console.log;
var b = "a";
String.prototype.htmlSafe = function(){
   this._html_safe = true;
   print(this === b);  // -> false
   return this;
}
String.prototype.htmlSafe.apply(b, []);

なんかそうっぽい。

var a = new String("a");
String.prototype.htmlSafe = function(){
   this._html_safe = true;
   print(this === a);  // -> true
   return this;
}
a.htmlSafe();

OK。それはともかく、元の値には影響を及ぼさないので、拡張する副作用系メソッドを定義する場合には、return this; を必ずつけて、

var a = b.htmlSafe();

のようにやるのがよさそうですね。

  • まぁでも、Rails の htmlSafe() のようなやり方よりも、そもそも <%= %> じゃなく [%= %] とか別のラベルにすればいいじゃん、と思っている。
  • ところで、javascript + "オートボクシング" で検索するとJavaが引っかかって邪魔なことこの上ない。