最近AngularJSを勉強し始めたのですが、調べ物をしているとデータを表示する時にjsonファイルを利用していることが多く見受けられるのですが、なぜjsonなのでしょう。
javascriptの配列ではだめなのでしょうか。
もしくは配列を使うのも同じくらい一般的なのでしょうか。
例えば、大学の時間割のアプリを作りたいとします。
データ1つに対する項目として、
・曜日(0=mon,1=tue...)
・時限
・授業名
・先生の名前
・教室
などがあるとします。
配列の場合だと
javascript
1[1,2,"有機化学","山田","3-D"], 2[2,3,"無機化学","田中","1-B"]
のように非常に簡潔に書けますが、jsonだと
json
1 { 2 "week":1, 3 "time":2, 4 "subject":"有機化学", 5 "teacher":"山田", 6 "room":"3-D", 7 }, 8 { 9 "week":2, 10 "time":3, 11 "subject":"無機化学", 12 "teacher":"田中", 13 "room":"1-B", 14 }, 15
のようになりますが、10個くらいなら確かにコードも読みやすくていいと思うのですが、
これが100種類、200種類になるとデータ量が「無駄に」膨大になるしメリット薄い気がするんですが、実際どうなんでしょうか。
これはAnglarJSで使う場合の話です。
あと、少し話がそれますが、
ng-repeatは「全」項目をリピートしますが、実際「全」項目リピートってそんなに使うかなって思うんですが、あるとすれば例えば時限が「2」のもの曜日が「1」のもののように、膨大なデータの中から条件を決めて抽出するほうだと思います。
こういうときって普通にifなどで絞り込んでからng-repeatを用いるのですか?
質問ばかりで恐縮ですが、よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答8件
0
そもそもJSONとは、'JavaScriptObjectNotation'の略で、「javascriptにおける'オブジェクト'を表現するための記法」のことです。すなわち、JSONデータ = javascriptにおけるオブジェクトです。
複数のデータをまとめる際に何故配列ではなくJSONを使うかというと、「その方が扱いやすいから」です。
例えば、質問内で提示されているデータの内容を表示するとき、配列とJSONではそれぞれ以下のようになるでしょう。
html
1<!-- 配列の場合 --> 2<h3>科目: {{ data[2] }}</p> 3<div> 4 <p>曜日: {{ data[1] }}</p> 5 <p>時限: {{ data[0] }}</p> 6</div> 7<div> 8 <p>教室: {{ data[4] }}</p> 9 <p>教員: {{ data[3] }}</p> 10</div> 11 12<!-- JSONの場合 --> 13<h3>科目: {{ data.subject }}</p> 14<div> 15 <p>曜日: {{ data.week }}</p> 16 <p>時限: {{ data.time }}</p> 17</div> 18<div> 19 <p>教室: {{ data.teacher }}</p> 20 <p>教員: {{ data.room }}</p> 21</div> 22
両者を比較してみて、いかがでしょうか。
配列の場合、2=科目、3=教員といった対応付けを全て覚えていないと、出力される内容が適切どうか把握できません。
一方、JSONの場合はデータそれぞれに名前を付けることができる=データに意味を持たせることができるので、人間に理解しやすくなります。上のJSONの例では、「教室」と「教員」が入れ替わっていることが一目瞭然ですね。
(配列の例では**「曜日」と「時限」も入れ替えてあります**が、すぐに気づけたでしょうか)
10個くらいなら確かにコードも読みやすくていいと思うのですが、
これが100種類、200種類になるとデータ量が「無駄に」膨大になるしメリット薄い気がするんですが、実際どうなんでしょうか。
配列の内容が100、200になった時、果たして100~200種類もの数字<=>データの対応付けを、を全て人間が覚えておけるでしょうか。
一見すると配列の方が記述量が少なくお手軽に見えますが、配列はあくまで同じ種類のデータをまとめて管理するためのものです。種類の異なるデータを複数まとめて取り扱いたい場合は、JSON等のオブジェクトという形でまとめるのは、javascriptに限らない定跡だと思います。
膨大なデータの中から条件を決めて抽出する
こちらの質問について、私はAngularJSそのものにはあまり詳しくないのでAngularJSにズバリな機能があるかはわかりませんが、「条件を満たす値のみを配列から抽出する」という用途であれば、filterというメソッドがArrayオブジェクトに存在します。
javascript
1var data = [1, 2, 3, 4, 5, 6]; 2var odd = data.filter(function(val) { 3 return val % 2 !== 0; 4}); 5var even = data.filter(function(val) { 6 return val % 2 === 0; 7});
selectメソッドは、引数に渡されたコールバック関数を配列の要素ごとに実行します。そして、コールバック関数がtrueの値を返した要素のみをまとめた配列を新しく作ります。
上の例では、oddには[1, 3, 5]という配列が、evenには[2, 4, 6]という配列が入ります。
このような方法で値にフィルタリングをかけてから、ng-repeatに配列を渡すのはいかがでしょう。
投稿2017/04/10 15:54
総合スコア267
0
この質問のポイントは配列とjsonの違いというより、配列と連想配列の違いな気がします。
javascript
1//配列版 2var hoge = [2,'無機化学']; 3//↓遠くのどこか 上の情報はスクロールしないとみえない 4week = hoge[0] 5subject = hoge[1] 6 7//連想配列版 8var hoge = {'week':2,'subject':'無機化学'}; 9//↓遠くのどこか 10week = hoge['week'] 11subject = hoge['subject']
これだとまだ大した違いはないですが、そこにtimeを入れることになったときは
javascript
1//配列版 2var hoge = [2,3,'無機化学']; 3//↓遠くのどこか 4week = hoge[0] 5time = hoge[1] // ←ここと 6subject = hoge[2] // ←ここを変える必要がある 7 8//連想配列版 9var hoge = {'week':2,'time':3,'subject':'無機化学'}; 10//↓遠くのどこか 11week = hoge['week'] 12time = hoge['time'] //←ここだけでいい 13subject = hoge['subject']
みたいになります。連想配列なら修正時にその要素が何番目になるのか、そして他の要素がどのようにずれるのかを考える必要がなくなるし、ラベルがそのままの意味なので勘違いによる間違えがでにくくなります。
配列だと予めしっかり設計していないと、1箇所変更するために100ファイル変更しないといけないとかもあり得るわけで、後でぐちゃぐちゃ変える可能性があるところでは使いにくいです。
jsonを使うと確かに配列よりも通信量は大きくなりますが、現代の通信環境ではそれほど大きな問題になるほどの差はなく、それよりもメンテナンス性の向上の方が価値があると考える人たちがjsonを採用したわけです。フレームワークであるAngularJSは、ちょっと通信量が多くなっても変化に強いことの方を選んだわけですね。
ここまでjsonびいきなことを書きましたが、配列の方がいい場合もあります。それは単一のテンプレートに当てはまる情報を大量に扱う場合です。カンマで文字列を繋げたCSVフォーマットとかがそれです。
通信量や通信時間やキャッシュするデータ量を気にするようなときに選びます。
要はそれぞれメリットデメリットがあるから、選択権がある人がそれらから最適と考えるものを選ぶわけです。その選択が良かったかそれともまずかったかは、使う各人が判断していいと思います。
投稿2017/04/10 16:24
総合スコア1895
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
配列の要素のみだと、データの中身にどういうデータが格納されているのかが判別しにくいです。
「week」や「subject」等の名称をkeyにして格納することで、
どういう値を参照しているのかがわかりやすくなります。
これが100種類、200種類になるとデータ量が「無駄に」膨大になるしメリット薄い気がするんですが、実際どうなんでしょうか。
逆に、100種類、200種類のデータになった時に、単純に配列に値を入れているだけでは、
配列の何番目に何の値が入っているのかがわからなくなります。
文字列ならまだしも、数値だったら、その値が「金額」を表しているものなのか、単なる「フラグ」なのか、判断できませんよね?
そのため、オブジェクトととして、要素名を決めて値を格納することで、
コードの見通しが良くなると思っています。
ng-repeatは「全」項目をリピートしますが、実際「全」項目リピートってそんなに使うかなって思うんですが、あるとすれば例えば時限が「2」のもの曜日が「1」のもののように、膨大なデータの中から条件を決めて抽出するほうだと思います。
こういうときって普通にifなどで絞り込んでからng-repeatを用いるのですか?
実際のコードがどういうコードなのかがわからないので、何とも言えないんですが、
自分はAngularに限らず、Reactなどでも、必要な項目だけをリピートしてますよ。
データの構造などにもよりますけど。
リピートしてコードを出力するということは、レンダリングコストもかかって、処理が重くなるので、
必要に応じて、内部でデータを加工したりしてng-repeatなどを実行したりしています。
投稿2017/04/10 16:00
編集2017/04/10 16:03総合スコア217
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
配列初期化子とオブジェクト初期化子
既に指摘があるように「JSONと配列の違い」ではなく、「配列初期化子([]
)とオブジェクト初期化子({}
)の違い」ですね。
JavaScript
1// 二次元配列 2[ 3 [1,2,"有機化学","山田","3-D"], 4 [2,3,"無機化学","田中","1-B"] 5] 6 7// 配列初期化子 + オブジェクト初期化子 8[ 9 { 10 "week":1, 11 "time":2, 12 "subject":"有機化学", 13 "teacher":"山田", 14 "room":"3-D", 15 }, 16 { 17 "week":2, 18 "time":3, 19 "subject":"無機化学", 20 "teacher":"田中", 21 "room":"1-B", 22 } 23]
JSONファイルを管理する
私は配列初期化子とオブジェクト初期化子のどちらであっても問題はないと考えています。
基本的に JSONファイルは手書きで編集するものではなく、機械的に書き換える方法を用意する方が合理的だからです。
先のデータは二次元配列に出来る以上、CSVやDBで管理する事が可能であり、CSVならExcelで入力、DBならサーバサイドスクリプトで管理する為のプログラムを書けば、プログラムを理解できない人にも編集は容易でしょう。
ただし、二次元配列にする場合は1列目に列名を指定すべきだと思います。
JavaScript
1[ 2 ["week","time","subject","teacher","room"], 3 [1,2,"有機化学","山田","3-D"], 4 [2,3,"無機化学","田中","1-B"] 5]
これでこのデータをCSV/DBに取り込むことが容易となりました。
JSONフォーマットは機械的に変換しやすい形式である事が重要であり、その点を守れば、どんなフォーマットでも良いと私は考えます。
Date.prototype.getDay
・曜日(0=mon,1=tue...)
曜日は Date.prototype.getDay
に準拠し、「0 = 日曜日, 1 = 月曜日, ...」にするとJavaScriptから扱いやすくなると思います。
CSV フォーマット
機械的な変換が容易であれば、JSON に拘る必要もありません。
JSON が広く使われているのは JSON パーサがネイティブで実装されており、コードに書き表すのが容易だからです。
パーサさえ用意すれば、どんなフォーマットであっても構いません。
先の二次元配列データはCSVで書き表すことも可能ですので、CSVフォーマットにする選択肢もあります。
week,time,subject,teacher,room 1,2,有機化学,山田,3-D 2,3,無機化学,田中,1-B
CSV は JSON よりもサイズ軽減できるメリットがある為、ファイルサイズを気にされるのでしたら要件に合致するかもしれません。
標準でCSVパーサは用意されていませんが、CSVは比較的シンプルな仕様なのでいくつかライブラリが出ており、場合によってはご自身で書くこともありだと思います。
参考までに、過去に私が書いたライブラリを紹介しておきます。
更新履歴
- 2017/04/13 01:16 Date.prototype.getDay を追記
- 2017/04/13 02:04 CSV を追記
Re: cloudspider さん
投稿2017/04/12 16:08
編集2017/04/12 17:05総合スコア18189
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
コンパイラー言語ならば
enum { ID = 0, NAME = 1, } int id = record[ID] string name = record[NAME]
などとすれば効率と可読性を両方満足させることができますが、ご存知のようにクライアントサイドでサーバーからの情報を解釈することはjavascriptにゆだねられています。この言語が意味的なチェックを実行時に行う動的型付けのインタープリタ言語である事情から、インターフェースを事前に形式的・厳密にチェックできない(それは軽快な開発ができることの代償だと思います)ため、JSONのような自己説明的なデータ形式の方が
let id = record.id
let name = record.name
のように直接系かつ明快にかけるという一点において「一定以上の品質を担保するために必要」と考えられているからではないでしょうか。もちろんjavascriptでも、
const ID = 0, NAME = 1;
let id = record[ID]
...
などと書けはするわけですが、const ID = 0
がインターフェース先となるサーバー側の定義と一致しているかどうかはキーが名前でない(つまり直感的でない)ため、何か機械的な事前チェックでもない限り「間違いの元になる」と多くの開発者が感じるのではないかと思います。そもそもキーが数字で充分なのであれば構造体のメンバーを名前でアクセスできるといった一般の言語の機能は必要ないということになってしまいますね。
これが100種類、200種類になると
一つのレコードにぶら下がる属性の種類が数十以上にもなるような設計は一般的でないと思います。つまりJSONで何十もの属性を表現する場面が一般的とはいえないと思います。
一方同一の形式のものを複数扱うという場面ならjavascriptでも普通に配列を使うことでしょう。「それぞれ意味が異なる個別の属性の表現」と「内容が全て同じのものの列」を質問者さんは同列に比較しているように感じますが、自分は「それらは区別して考えるべきもの」というふうに思います。
ただ、JSONは冗長なデータ表現であることは質問者さんがおっしゃるとおりだと思います。正直自分もそう思いました。しかし前述したような話と、現在の計算機の処理能力・通信インフラの能力などのバランスを考えたとき、JSONのような冗長な形式でも充分実用になるということなのだと思います。そもそもがHTMLやXMLはバイナリーに比べると冗長きわまる形式ですが、今日それが「冗長すぎて効率がわるい!全部バイナリーにすべき」という人はあまりいないと思います。(XMLやHTMLにはその形式を厳密に定義するDTDがありJSONにはないという違いはあるでしょうから一概に同じとはいえないかも知れませんが、人間がそれを見て直感的に意味を把握しやすい可読可能なテキストになっているという点では似ていると思います。)
他にも色々と理由はあるかも知れませんが素朴な感覚からコメントしてみました。
投稿2017/04/10 16:32
総合スコア18400
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
10個くらいなら確かにコードも読みやすくていいと思うのですが、
これが100種類、200種類になるとデータ量が「無駄に」膨大になるしメリット薄い気がするんですが、実際どうなんでしょうか。
JSONに限った話ではありませんが、
HTMLやCSS、JSONなどのファイルはサーバとクライアント間の通信時にgzipで圧縮されます。
なので、テキストファイルの送受信は多少膨大になっても高圧縮に出来るのであまり気にする必要はありません。
画像ファイルはアイコンレベルでも60kBみたいな馬鹿でかいファイルサイズになりますからね…
通信さえ行われてしまえば後は大差ないですね。
万に届くデータ量も瞬時に解析出来るので連想配列でのやり取りが一般的となっています。
ng-repeatは「全」項目をリピートしますが、実際「全」項目リピートってそんなに使うかなって思うんですが、あるとすれば例えば時限が「2」のもの曜日が「1」のもののように、膨大なデータの中から条件を決めて抽出するほうだと思います。
こういうときって普通にifなどで絞り込んでからng-repeatを用いるのですか?
その通り、一般的には配列を返す関数を用意してあげると良いでしょう。
HTML
1<div ng-init="time=2; week=1"> 2 <table> 3 <tr ng-repeat="user in filtered_users(users, time, week)"> 4 </table> 5</div>
JavaScript
1// 大抵はスコープの中で宣言するのでこんな感じ? 2$scope.filtered_users = function(users, time, week){ 3 if (users == null) return []; // usersがundefinedの場合エラーが出るので逃げる 4 return users.filter(function(user){ 5 return (user.week === week) && (user.time === time) 6 }) 7}
投稿2017/04/12 05:35
総合スコア21194
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
JSONでも配列で書く方法はあります。
json
1[ 2 [1,2,"有機化学","山田","3-D"], 3 [2,3,"無機化学","田中","1-B"] 4]
しかしこれだとtopoさんの言うとおりでこれだとデータの関連付けが難しくなります
しかしforのループ処理ですべてのデータを場合になると少し変わってきます
ループで文字列を使いたい場合はもう一つ配列を作ってその配列の値をkeyとして取得するというすこし遠回りな方法になります
js
1var key = ["week","time","subject","teacher","room"]; 2for(var i=0;i<json.length; i++) { 3 json[key[i]] 4}
その時にあった書き方を選ぶと良いと思います
投稿2017/04/10 16:41
総合スコア270
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/04/12 01:41
2017/04/12 04:51
2017/04/12 05:08 編集