no-image

Javascript #配列

JSに対して不勉強だったツケがきた

DatatablesでJSONを表示するコードを今まで書いてきて、なあなあでなんとなく動くコードを使っていたのだけれど、今回はいろいろカスタマイズしたいなーって思うようになってきました。
JSONはまあ配列なのでそれを扱えるようになればオッケーなんですが、そもそもJSを触ったのが一年くらい前で変数宣言にvar使うことくらいしか知らないくらいにド素人なので苦戦しました。
なので次は苦戦しないように忘備録として記事にしたいと思います。

やりたいこと

JSON形式でデータをもらったら、それをテーブルに表示したい。表示するのにはDatatablesを使う。オプション機能とかめっちゃあってすごく便利そうなのに、JSがわからなさすぎて全くイカせていない

入力データ

入力データはsplatoon2の過去の全戦績の統計。統計といっても公式サイトから得られる情報はガチマッチのそれぞれのステージごとの勝利数くらいしか取得できない。
ということで、それぞれの勝利数を合計してガチマッチ毎の勝率を計算してみたわけである。ナワバリバトルだけは勝率のデータが残っていないので単純には計算できないのだが、総合の勝利数と敗北数のデータがあるため、そこからガチマッチの合計を引けばそれぞれ勝利数と敗北数が求められるわけである。
そうやって求めた値を配列に入れて、JSONに整形したデータが以下の通り。

{
    "total": {
        "type": "total",
        "win": 1036,
        "lose": 966,
        "ratio": 0.5175
    },
    "turf_war": {
        "type": "turf_war",
        "win": 420,
        "lose": 436,
        "ratio": 0.4907
    },
    "rainmaker": {
        "type": "rainmaker",
        "win": 217,
        "lose": 201,
        "ratio": 0.5191
    },
    "tower_control": {
        "type": "tower_control",
        "win": 95,
        "lose": 85,
        "ratio": 0.5278
    },
    "splat_zones": {
        "type": "splat_zones",
        "win": 184,
        "lose": 158,
        "ratio": 0.538
    },
    "clam_blitz": {
        "type": "clam_blitz",
        "win": 120,
        "lose": 86,
        "ratio": 0.5825
    }
}

typeっていう要素はいるのか?っていう気もするけれど、のちのちなにか使いそうだからおいておく。

HTML

HTMLには必要最低限のことしか書かないのでめちゃ楽。


Javascript

ここが一番の問題でした。

$(document).ready(function() {
  var table = $("#stats-main").DataTable( {
    "order": [0, 'desc'],
    ajax: {
      url: "stats.json",
      dataSrc: function(json){
        for(var key in json){
          console.log(json[key]);
        }
      }
    },
    columns: [
      { data: "win" },
      { data: "lose" },
      { data: "ratio" },
    ],
    lengthChange: false, //件数切り替え機能無効化
    searching: false, //検索無効化
    info: false //テーブル情報非表示
    paging: false  //ページング無効化
    } );
  } );

当たり前だけれど、columnsの行のコードは動かない。
dataSrcっていうところがキモになっていて、ココに関数を書くことでいろんなことが実現できる。ココで面白いのは、

function(json){
  //処理
}

と書けば、読み込んだJSONファイルが自動的に変数jsonに格納されているところ。ということは実際のデータにアクセスしたければ単純に配列にアクセスするだけで良い。

配列へのアクセス

PHPで連想配列にアクセスする場合は、要素名が定数であれば

$array->name;
$array["name"];

などで実現できた。
javascriptの場合は、

array.name;

で実装することができる。つまり、例えばjson.turf_warとすると良いわけである。しかしこれではfor文でまわす際に毎回同じ要素にアクセスしてしまうという問題が発生する。
PHPの場合はforeach文を使うことでこれが回避できて、

foreach($array as $val){
  echo($val);
}

のようなコードで実装できた。
同じことをjavascriptでやろうとするとinというメソッドがあるのでそれを利用してみるとおかしなことになる。

for(var key in json){
 console.log(key);
}
//実行結果
total
turf_war
tower_control
rainmaker
splat_zones
clam_blitz

このコードはjsonの要素名を全て返すコードとして働いてしまう。つまり、本の中身が読みたいのにタイトルだけ返してしまっているような状態になっている。
かといって下記のようなコードは動作しない。というのはkeyという要素名はないからだ。ここではちゃんと配列としてアクセスしなければいけないので後者のように記述する。これは正しくすべての配列の中身を返す。

for(var key in json){
 console.log(json.key); //keyという要素名はない
 console.log(json[key]); //正しく動作する
}

forEachを使う

実はjavascriptにもforEach文が存在する。(ないのはC言語くらいではないのか…)forEach文の良いところはとにかく配列が扱いやすいこと
ただし、javascriptのforEach文は他の言語とちょっと書き方が違う。前提条件として変数名objに配列のデータが全て入っているものとする。

obj.forEach(function(val){
  console.log(val);
});

こうすれば簡単に配列のループが実現できる。ただし、これはオブジェクト形式にしか対応しておらず、連想配列のJSONでは使うことができない(意味ないじゃん)
一応Objectを使えばJSONに対してもコードが書ける。ちなみに以下の二つのコードは等価である。

Object.keys(json).forEach(function(val){
  console.log(json[val]);
});
for(var key in json){
  console.log(json[key]);
}

これなら「普通にfor文で回したほうがいいんではないか?」っていう気になりますね。

テーブルで表示されるように

ここまではJSON形式のデータをjavascriptで扱う方法を述べた。ただしこのままではコンソール出力されているだけでテーブルとして扱えていない。
やろうとおもったけれど、めんどくさそうなので一旦中断。

JSONをリスト形式にできるか

次は詳細な履歴を実際のデータと繋ぐところである。
ソースコードを読めば次のようなコードを書けば上手くリンクが貼れるようである。

<li class="victory ">
  <a class=" internal-link" href="/results/1995">
    <div class="order">WIN!</div>
    <div class="result-contents">
      <div class="weapon">
        <img class="weapon-image" src="" alt="スパッタリー"></div>
      <div class="stage">ガンガゼ野外音楽堂</div>
      <div class="point">1169p</div>
    </div>
  </a>
</li>

このようなデータの取得するのは全く難しくない。実際にデータにアクセスする際は保存しているjsonを参照するのでそこまで細かいデータを保存しておく必要がないからだ。
となると、塗りポイント、ブキ、勝敗、バトルの種類、バトル番号くらいをデータベースに保存しておけば良さそうである。もちろん実際にはフェスだとかリーグマッチだとかプライベートマッチがあるのでそこまで少なくはないだろうが、コーディングするのがめんどくさいほど多いというわけではなさそうだ。
つまり、データをとってくるのは問題ない。それをJSON形式で出力するのも全く問題ない。
問題はJSONのデータを非同期(ajax)を使ってこのように整形する部分である。ソースコードに直書きなんてことはしたくないのである。

このお話はまだまだつづくのじゃ。