概要
例えば、JavaScriptでいろんな台詞を表示したいとします。
すると、大抵は台詞のデータを配列に書くことになると思うのですが…
var dialogueList = [
"あいうえお",
"かきくけこ",
"さしすせそ",
"たちつてと",
"なにぬねの",
"はひふへほ",
"まみむめも",
"やゆよ",
"らりるれろ",
"わゐゑを",
"ん"
];
こうなります。
台詞1つ追加する度に、引用符にカンマをつけなくてはなりません。
また、エスケープも考慮しなくてはなりません。
エディタに補完機能が無い場合は、インデントも手動で打たなくてはなりません1。
これくらいなら数が少ないためまだ見やすいのですが、これが増えてくるともっと辛くなるかもしれません。
そこで、HTMLに改行区切りの文字を埋め込み、それを配列に変換するという方法を考えてみました。
コード
<!-- script要素でHTML内にデータを埋め込む -->
<script type="text/plain" id="dialogue_data">
あいうえお
かきくけこ
さしすせそ
たちつてと
なにぬねの
はひふへほ
まみむめも
やゆよ
らりるれろ
わゐゑを
ん
</script>
/*
* HTMLでscript要素に埋め込んだ文字列を取得する。
*/
var dataText = document.getElementById("dialogue_data").textContent;
/*
* 埋め込んだ文字列を配列に変換する。
*/
var dialogueList = dataText
/* 改行ごとに分割し、配列化 */
.split(/\r\n?|\n/)
/* 配列の要素の前後からスペースを取り除く */
.map(function(str) {
return str.trim();
})
/* 空文字列の要素は配列から除外する */
.filter(function(str) {
return str !== "";
});
[
"あいうえお",
"かきくけこ",
"さしすせそ",
"たちつてと",
"なにぬねの",
"はひふへほ",
"まみむめも",
"やゆよ",
"らりるれろ",
"わゐゑを",
"ん"
]
動作サンプル
データを配列で書くのが面倒なので、改行区切りの文字列をHTMLに埋め込んで配列に変換する
解説
原理は簡単です。
script
要素にテキストデータを書き、そのテキストをJavaScriptで読み込んで配列に変換しています。
script
要素はJavaScriptを使うための要素ではありますが、実はJavaScriptではないテキストも埋め込めます。
script
要素のtype
属性を省略せず、JavaScriptのMIMEタイプではない値を書けば、WebブラウザはそれをJavaScriptとして実行しなくなります。
「JavaScriptのMIMEタイプではない値」とは?
このセクションの説明について、著者は正しいと言い切れません。もし誤っていた場合は、コメントや編集リクエストで指摘してください。
仕様書では、「JavaScriptのMIMEタイプ」として以下のものが定義されています。
application/ecmascript
application/javascript
application/x-ecmascript
application/x-javascript
text/ecmascript
text/javascript
text/javascript1.0
text/javascript1.1
text/javascript1.2
text/javascript1.3
text/javascript1.4
text/javascript1.5
text/jscript
text/livescript
text/x-ecmascript
text/x-javascript
このような値が「JavaScriptのMIMEタイプ」になります。
ただし、これ以外の値であればなんでも良いかと言うと、そうではありません。
将来的に、WebブラウザがJavaScript以外の言語をscript
要素で読み込めるようにしてしまうかもしれません。
例えばGoogle Chromeでは、一時期Dartという言語を扱えるようにしようとしていました。もしそうなっていたら、以下のようなHTMLでDartが使えるようになっていたかもしれません。
<script type="application/dart">
main() {
print('Hello, Dart!');
}
</script>
すると、type
属性にapplication/dart
という値を指定して好き勝手なテキストを埋め込んでいるHTMLは、JavaScriptと同じように実行エラーを起こしてしまいます。
このような問題を防ぐため、type
属性に指定する値は「言語として実行されないと定まっている値」を指定した方がいいと思います2。
例えば、仕様書で「言語として実行されない」と定義されている以下の値がこれに該当します。
text/plain
text/xml
application/octet-stream
application/xml
この記事で例示したような「独自形式のテキストデータ」の場合はtext/plain
が適切だと思います。
外部ファイル化したいのでsrc
属性で読み込みたい…
このコードは**src
属性での外部ファイル読み込みに対応していません**。
そもそも、独自形式のテキストデータをscript
要素で埋め込むこのやり方とsrc
属性は相性が悪いため、私は推奨できません。
というわけでこの記事では、外部ファイル読み込みに対応させたコードは記載しないことにしています。
例えば以下の様な記述をした場合、Webブラウザは普通のJavaScriptと同じように「dialogue-data.txt
」ファイルを読み込みます。
<script type="text/plain" src="dialogue-data.txt" id="dialogue_data"></script>
しかし、これはJavaScriptとして処理されません。
そしてこの読み込まれた「dialogue-data.txt
」ファイルのデータをJavaScriptは使用できません3。
このため、Ajax4で再び「dialogue-data.txt
」ファイルを読み込み、そのデータを習得しなくてはなりません。
つまり、二回も「dialogue-data.txt
」ファイルを読み込まなくてはならなくなります。
通信量の無駄ですし、その分実行速度が遅れてしまいます。
この事から、この方法とsrc
属性での外部ファイル読み込みは相性が悪いと私は考えています。
Internet Explorer 8で動作しない
上記のコードはECMAScript5で追加された関数を多用しているため、IE85では動きません。
代わりにjQuery版を使ってください。
ただ、そもそもIE8などというMicrosoftのセキュリティサポートが切れた負の遺産を使い続ける事そのものが問題なので、可能であればIE8で動かそうなんて考え自体を捨てましょう。
jQuery版
もしかしたら需要があるかもしれないので、jQueryでのコードも書いてみました。
HTMLは同じなので省略。
/*
* HTMLでscript要素に埋め込んだ文字列を取得する。
*/
var dataText = $("#dialogue_data").text();
/*
* 埋め込んだ文字列を配列に変換する。
*/
var dialogueList = $.map(dataText.split(/\r\n?|\n/), function(str) {
/* 配列の要素の前後からスペースを取り除く */
var newStr = $.trim(str);
/*
* 要素が空文字列の場合、nullを返して配列から削除
*/
if (newStr !== "") {
return newStr;
} else {
return null;
}
});
動作サンプル
データを配列で書くのが面倒なので、改行区切りの文字列をHTMLに埋め込んで配列に変換する [jQuery版]
同じような例
このようなアイデアは、別に新しいものではありません。
例えばHandlebarsというテンプレートエンジンも、以下のような記述で独自形式のテンプレートをHTMLに埋め込んでいます。
<script id="entry-template" type="text/x-handlebars-template">
<div class="entry">
<h1>{{title}}</h1>
<div class="body">
{{body}}
</div>
</div>
</script>
またJSON-LDでも、以下のようにして独自のJSONデータをHTMLに埋め込むことができます6。
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "Person",
"name": "sounisi5011",
"url": "http://qiita.com/sounisi5011"
}
</script>
-
インデントはJavaScriptの実行とは無関係なので無理して打たなくても良いといえば良いのですが、読みにくさが増して保守性が悪化しますので大抵の人間は打つと思います。 ↩
-
このような基準が明確に示された文書や資料、仕様を見たことは無いため、これはあくまで私の考えです。 ↩
-
少なくとも私は、「Webブラウザが勝手に読み込んだファイルのデータをJavaScriptで読む」方法を知りません。 ↩
-
雑な表現をするならば、JavaScriptでファイルを読み込んでそのデータを取得する機能です。 ↩
-
Internet Explorer 8の事は「IE8」と表記されることがよくあります。 ↩
-
JSON-LDの場合はMIMEタイプが
application/ld+json
で決まっているため、type
属性はこの値になります。 ↩