38
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScriptで配列を直接書くのが辛い時は、script要素に文字列を埋め込めば良いかもしれない

Last updated at Posted at 2016-08-22

概要

例えば、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 !== "";
  });
変数dialogueListに格納されるデータ
[
  "あいうえお",
  "かきくけこ",
  "さしすせそ",
  "たちつてと",
  "なにぬねの",
  "はひふへほ",
  "まみむめも",
  "やゆよ",
  "らりるれろ",
  "わゐゑを",
  ""
]

動作サンプル

データを配列で書くのが面倒なので、改行区切りの文字列を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>
  1. インデントはJavaScriptの実行とは無関係なので無理して打たなくても良いといえば良いのですが、読みにくさが増して保守性が悪化しますので大抵の人間は打つと思います。

  2. このような基準が明確に示された文書や資料、仕様を見たことは無いため、これはあくまで私の考えです。

  3. 少なくとも私は、「Webブラウザが勝手に読み込んだファイルのデータをJavaScriptで読む」方法を知りません。

  4. 雑な表現をするならば、JavaScriptでファイルを読み込んでそのデータを取得する機能です。

  5. Internet Explorer 8の事は「IE8」と表記されることがよくあります。

  6. JSON-LDの場合はMIMEタイプがapplication/ld+jsonで決まっているため、type属性はこの値になります。

38
38
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?