nmi.jp Twitter → @tkihira
Convertible Note / Convertible Equity とは? WordPressからJekyllにブログシステムを移行

JavaScriptのヒアドキュメントあれこれ


2016-07-03
Takuo Kihira

JavaScriptのヒアドキュメントでちょっと苦労したので、少し書いておきます。

皆様御存知の通り、JavaScriptにはヒアドキュメントの文法がありません。ヒアドキュメントというのは、改行やホワイトスペースも含んだ文字列リテラルを表現する文法の呼称です。例えば

var heredoc = <<EOS
<html>
  <head>
    <title>Here Document</title>
  </head>
  <body>...</body>
</html>
EOS;

みたいな感じの文法です(もちろんJavaScriptでは上記は動作しません)。

今回自分が必要だったのは、とあるテンプレートエンジンを使用すると } のところに <script>...</script> が埋め込まれてしまうのですが、そのスクリプトの中身を書き換えたくて何とか文字列リテラルとして取得したい、という状況でした。

こういう時によく見かけるのが、FunctionのtoStringを使う方法です。

var heredoc = (function() { /*
ababababab...
ababababab...
*/}).toString();
console.log(heredoc);

これを実行すると

function () { /*
ababababab...
ababababab...
*/}

この文字列を取得出来るので、正規表現などを使ってここから内容を取得する方法です。

これには問題点が大きく2つあります。1つ目は、Function#toStringは実装依存で、ブラウザに妙なセミコロンやスペースを挿入されても仕様違反ではないということです。実際、Safariの昔のバージョンはそういう問題を持っていたらしいですね。2つ目は、JavaScriptの文法として考えるとヒアドキュメントの部分はコメントなので、minifierみたいなツールで消されてしまう可能性があることです。

まあ、あまり積極的に使わない方が良いと思います。

ブラウザのDOMを使った方法としては、<script>タグで真っ当に読み込む方法もありますね。WebGLのShaderを読み込む時などに積極的に使われている印象がありますが、スクリプト以外の物を読み込むのには少し抵抗があります。

<script language="heredocument" id="heredoc">
heredoc
</script>
<script>
var heredoc = document.getElementById("heredoc").text;
console.log(heredoc);
</script>

今回私がハマったのは、ヒアドキュメントの内部に</script>という文字が入ってしまったために、そこでブラウザがスクリプトタグを閉じてしまい、結果としてパースエラーになりました。DOMを使う方法も同じ理由で無理です。

<script>
var heredoc = (function() { /*
<script>
...another javascript program...
</script> // ←ブラウザが勘違いしてここでタグを閉じちゃう
*/}).toString();
console.log(heredoc);
</script>

これどうしようかな〜と思っていた時に、グニャラくん素晴らしい?方法を教えてもらいました。なるほど、この方法ならば</script>が入っていても問題ないですね!

実際の所、このような方法に頼らなくてはいけなくなった時点で根本的な解決を探す方が良いとは思いますが、最後の手段としての知識としては面白いのでご紹介しました。