はじめに
JavaScriptのオブジェクト型データがよくわからない方のために、重要ポイントを基本から応用までまとめました。
データの基本操作からJSONの活用、連想配列、オブジェクト指向の考え方やモデル化の概念、ソースコードを速読するためのコツを解説しています。
オブジェクト型データの基本文法
###オブジェクト型データの定義方法
let person = { name: "ICHIRO", age: 20 }
nameの部分をプロパティ、"ICHIRO"の部分を値と呼びます。key/valueと表現したほうがわかりやすいかも。
オブジェクト型は中括弧{}の外殻の中に、複数のkey:valueセットをカンマ区切りで格納することができます。
###オブジェクト型データの参照方法
person.name // ICHIRO
person.age // 20
変数名にドット演算子「.」を付与して、key文字列を記述すると、valueが取り出せます。
nameもageもpersonに関する情報だということが一目でわかるので、とても便利。
###オブジェクト型データの編集方法
person.name = "イチロー" // keyに紐づくvalueの上書き更新 ( update )
person.job = "baseballer" // いきなりkeyとvalueのセットを追加可能 ( insert )
delete person.age // ageのkeyと紐づくvalueを削除する ( delete )
データベースのSQLのように、格納したデータのCRUD操作すべてが可能です。
オブジェクト型データの削除は、delete文を使います。
###オブジェクト型データに関数を持たせる(メソッドの設定)
// 基本的な記述方式
person.throw = function(){
console.log("投げます!");
};
// ES6以降の最新の記述方式
person.hit = () => console.log("打ちます!");
// 実行する場合
person.throw(); // 投げます!
person.hit(); // 打ちます!
オブジェクト型データに関数を格納して実行することもできます。
なお、オブジェクト型に持たせた関数は、「メソッド」と呼ばれます。
この場合、現実世界の「人」をモデル化した「person」の動きを表現するのがperson.throw()やperson.hit()になりますので、そういった意味で関数ではなく、メソッドと呼んだ方が確かにしっくりきます。
メソッドの記法は、平成時代のfunctionを使った定義方式と、令和時代のECMA2015(ES6)における定義方式の2通り用意しました。
実行時には()を付与することになっていますので、他人のソースコードを読んでいる時にもメソッドであることがすぐにわかりますね。
##連想配列
連想配列は、オブジェクト型データを別の記法で表現したもので、データそのものは全く同一です。
###連想配列の記述方式
let person = {}; // 空のオブジェクト型データの生成
person["age"] = 20; // person.age = 20; と全く同じ
連想配列の記法は、ブラケットの中にkeyとなる文字列を指定するだけです。
###連想配列記法を使う利点
ところが、連想配列の記法を使うと、より柔軟な操作をオブジェクト型データに実行することができます。
let str1 = "weight"
person[str1] = 78; // person.weight = 78; と同じ
オブジェクトのkeyに、文字列格納済みの変数を設定することができています。
この性質を利用すると、例えば以下のように、for文でオブジェクトのkeyを一気に追加することも可能です
for(let i=0; i<3; i++){
let keyStr = `others0${i+1}` ;
person[keyStr] = "未設定";
}
このようなコードにより、以下のような結果が得られます
person.others01; // 未設定
person.others02; // 未設定
person.others03; // 未設定
for文により、オブジェクトのkeyを一気に3つ自動追加できたことになります。
その他、DBから読み込んだidをkeyに設定して、idに紐づくデータを値として持たせる、といったプログラミングも可能となります。
実際の開発現場では、そのようなコードを見る機会もあると思います。
オブジェクト型データの基本的な記述方式であるドット演算子を使ったやり方では不可能な操作が、ブラケット[]を使った連想配列記法では可能になるんですね。
###連想配列のネーミングの由来
ところで、「連想配列」ってなぜこのようなネーミングになったのか考えてみました。
まず、ブラケット[]を使っている時点で記法は配列ですね。配列と比較すると、index指定が違いますね。
let arrayData = []; // 配列型の定義
arrayData[0] = "こんにちは";
let objData = {}; // オブジェクト型の定義
objData["aisatsu"] = "こんにちは";
配列は0から始まる番号で番振りされますが、オブジェクト型は何か意味のある値をkeyにしますね。
「aisatsu」という文字列がkeyなので、だいたい値が何か連想できる。それで「連想配列」なのかなと思います。
##JavaScriptのオブジェクトとオブジェクト型データ
ところで、JavaScriptにはオブジェクトという概念があって、非常に幅の広い扱い方をされています。
例えばこちらの記事では、そういった「広義のオブジェクト」についての解説があります。
[JavaScript] オブジェクトの基礎
###組み込みオブジェクトとメソッド
特に重要なポイントとして、「組み込みオブジェクト」と「実装済みメソッド」を解説します。
オブジェクト型だと呼び方が紛らわしいので、配列型で見てみましょう。
let arrayData = ["パン", "茶"]; // 初期化データを2つ持った配列型データの定義
arrayData.push("宿直"); // pushメソッドで要素を1つ追加
このような基本的な配列型データを用意しているコードを見てみます。
ところで、.push()のドット演算子を使った記法はオブジェクト特有のものですよね。
しかも、.push()は配列型以外のデータで使おうとすると、エラーになります。
実は、配列型データはArrayクラスというオブジェクトから生成されたインスタンスであり、このArrayクラスのようなJavaScript標準で用意されたクラスのことを「組み込みオブジェクト」と呼びます。
Array - MDN web docs
JavaScript の Array クラスはグローバルオブジェクトで、高水準、リスト風のオブジェクトである配列の構築に使用されます。
そして、Arrayクラスは標準でpush()などのArrayクラス用メソッドが実装されています。
Array.prototype.push()
Javaに詳しい方はすぐにピンとくる話ですね。
Javaは、クラスを用意して、クラスからインスタンスを生成して、インスタンスからドット演算子により実装済みメソッドを実行できます。
JavaScriptでも、ほぼ同じような概念で組み込みオブジェクトの配列クラスを扱うことができます。
JavaScriptの場合は、インスタンス化作業は単なるクラスコードのコピー(clone)をprototypeというプロパティに格納して、そこからクラスに定義されたメソッドが実行できるという仕組みです。
なお、正式な配列型データの記法は、Arrayクラスからnewして生成します。
let arrayData1 = [] ; // 実はシンタックスシュガー構文
let arrayData2 = new Array() ; // 全く同じ配列型の初期化データを生成できる
JavaScript専門の方は、配列などの組み込みオブジェクトがあって、便利メソッドが実装済みで、それを使えばいいんだという理解でOKだと思います。
オブジェクトってイメージが大切なので、「なんか便利な配列さん」がいて、いろいろサービスを提供してくれる・・・みたいな理解で通用してしまいます。
この章はだいぶ話が難しくなってしまいましたが、広義のオブジェクトとオブジェクト型データの言葉の違いを理解していただければOKです。
また、組み込みオブジェクトって、だいたいオブジェクト型データみたいな扱いでメソッドを使えるんだなと思っていただけると、コードの速読スキルが上がるし、コードを書くスピードも上がると思います。
###オブジェクト型も組み込みオブジェクト
冒頭から解説しているオブジェクト型データの正式な記法は、Objectクラスからnewして生成します。
let objData1 = new Object(); // 正式な記法でクラスからインスタンス生成して定義
let objData2 = {}; // 実はシンタックスシュガー構文
要するに、本記事で解説しているオブジェクト型データとは、Objectクラスのコンストラクタを実行してnewして生成したインスタンスということになります。
Objectクラスのインスタンスですね。
配列の場合は、Arrayクラスのインスタンスです。インスタンスの概念が良くわからない場合、メルヘン世界で擬人化された生きた存在だと思っていただけると、けっこう通用します。これに対し、クラスは「設計図」だと言われています。インスタンスは、設計図から3Dプリンタで生成された実体で、しかも生きている感じなわけですね。
##オブジェクト型データとJSON
###JSONとは
JSONとは、JavaScript Object Notation の略で、直訳すると「JavaScriptオブジェクト記法」ということになります。
JSONとして扱えるコードは以下のようなものです
{ "name" : "ICHIRO", "age" : 20, "isSuccess" : true } // オブジェクト型データ
[ 1, 3, 5 ] // 配列型データ
{ "skills" : ["JavaScript", "HTML", "CSS" ] } // オブジェクト型と配列型の組み合わせ
要するに、JSONとはオブジェクト型、配列型の組み合わせを基本としたデータ形式です。
構造としてオブジェクト型と配列型を使い、値として文字列、数値、真偽値、オブジェクト型、配列型を指定します。値にオブジェクト型や配列を指定すると、入れ子構造になり、どんどん構造が複雑になり、様々なデータ形式に対応できます。
JavaScriptの記法でデータを表現すると、CSVデータの表現も簡単だし、多種多様な組み合わせでデータを表現できる。しかも、JSプログラム互換で便利ということで、今やJSONはAPIデータ通信フォーマットのデファクトスタンダートとなっています。
###JSONとJavaScriptオブジェクト
JSONとは、JavaScript言語の実行環境以外でも使える、共通の文字列データ仕様です。
データ構造は複雑ですが、JavaScriptでプログラミングしている分には簡単に構築することができます。
// JSONデータオブジェクトの生成例
let engineer = { name : "kenshirou" };
let languages = ["JavaScript", "HTML", "CSS"];
engineer.languages = languages
このような形で、オブジェクト型や配列型を別々に定義してから、後から一つに統合してJSON形式データが簡単に構築できるのですが、そのまま上記の「engineer」変数をAPIの引数に渡してもエラーになってしまいます。
JavaScript以外の言語や仕組みにも対応可能なJSONデータを生成するには、以下の処理が必要です
let json_engineer = JSON.stringify( engineer ); // シリアライズ処理を実行
これはJSON.stringfy()メソッドによるシリアライズ処理と呼ばれます。
どういうことかと言いますと、このような違いがあります
console.log( engineer );
console.log( json_engineer );
シリアライズ処理後のデータをconsole出力すると、改行無しのただの文字列が出力されることがわかると思います。
また、オブジェクト型データを定義した時にnameはダブルクォートで囲っていませんでしたが、自動で付与してくれています。
ただの文字列ということを別の側面でも確認できます。こちらのコードを見てください。
engineer.name // kenshirou
json_engineer.name // undefined
engineerはオブジェクト型データなので、ドット演算子でプロパティにアクセスできます。
ところが、json_engineerはただのString文字列なので、.nameのような記法は使用不可能なんですね。
##まとめ
JavaScriptにおけるオブジェクト型データの操作方法について、基本事項をまとめて解説しました。
オブジェクト型データの構造を自在に作れるようになると、何かと開発しやすいです。
これでプログラミングが楽しくなること間違いなし。