はじめに
本記事では、JavaScriptにおけるデータ型のオブジェクト型とシンボル型について周辺知識をまとめていきます。
今回の記事も以前書いた記事と同様に以下のサイトのチュートリアルを進める中で学んだことをまとめていますのでJavaScriptを勉強している、してみたい方は是非参考にしてください!
オブジェクトとは
早速本題である「オブジェクト」について説明していきたいと思います。
オブジェクトとは、キー付けされた様々なデータのコレクションや、より複雑なエンティティを格納するために使用されます。
- オブジェクトのきほん
波カッコと任意のプロパティから成り立ち、プロパティは “キー:値” のペアで、キーは文字列であり、値に制限はありません。
~記述例~
let user = new Object(); // "オブジェクトコンストラクタ" 構文
let user = {}; // "オブジェクトリテラル" 構文
//どちらの記述方法でも構いません。
let user = { // オブジェクト
name: "John", // キー "name" に値 "John" が格納される
age: 30 // キー "age" に値 30 が格納される
};
//この時のプロパティ数は2
プロパティの参照
初期化してあるオブジェクトのプロパティは以下のようにして参照します。
//オブジェクト名.プロパティ名
//例
alert( user.name ); // John
プロパティの追加
また、プロパティの追加を行うことが出来ます。
//オブジェクト名.追加したいプロパティ名 = 値
//例
user.isAdmin = true;
プロパティの削除
プロパティの削除には、delete
演算子を用います
//delete オブジェクト名.プロパティ名
//例
delete user.age;
空白を含むプロパティ名
空白を含むプロパティに対して.
(ドット)を用いてアクセスしようとするとエラーになります。そんな時に登場するのが[ ]
を用いたアクセスです。
早速使い方を見てみましょう
let user = {};
// set
user["likes birds"] = true;
// get
alert(user["likes birds"]); // true
// delete
delete user["likes birds"];
これで問題なく空白を含んだプロパティにもアクセスすることが出来ます。
- 使用制限
.
:スペースが含まれていない、数値から始まっていない、特殊文字が含まれていないなど
[ ]
:任意の文字列で動作
という風に[ ]
でアクセスする方がプロパティ名に対して柔軟に対応することが出来ます。
それでも予約語は用いることが出来ないことに注意してください。
in
演算子について
JavaScript では、どんなプロパティへもアクセスでき、プロパティが存在しない場合でもエラーにはならず、undefind
を返します。
ここでプロパティが存在するかどうかを確かめるin
演算子というものがあります。
let user = { name: "John", age: 30 };
//プロパティ名 in オブジェクト名
alert( "age" in user ); // true, user.age は存在する
alert( "blabla" in user ); // false, user.blabla は存在しない
~応用編~すべてのプロパティを確認する
オブジェクトの全てのプロパティを確認するにはfor文を用います。
let user = {
name: "John",
age: 30,
isAdmin: true
};
//確認
for(let key in user) {
// keys
alert( key ); // name, age, isAdmin
// values for the keys
alert( user[key] ); // John, 30, true
}
オブジェクトのクローン作製
オブジェクト変数のコピーは参照をもう一つ作ります。もしもう一る独立した変数の複製を作成したい場合、空のコンストラクタに初期化するかObject.assain
関数を用います。
最初に関数の使い方を紹介します。
Object.assign(複製先オブジェクト名[複製するプロパティ名, src1, src2...])
次に変数の複製を作成するソースコードを見ていきましょう。
let user = {
name: "John",
age: 30
};
let clone = {}; // 新しい空オブジェクト
// すべての user プロパティをその中にコピー
for (let key in user) {
clone[key] = user[key];
}
// 今、clone は完全に独立したクローンです
clone.name = "Pete"; // その中のデータを変更
alert( user.name ); // 依然としてオリジナルのオブジェクトは John
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// permissions1 and permissions2 のすべてのプロパティを user にコピー
Object.assign(user, permissions1, permissions2);
// now user = { name: "John", canView: true, canEdit: true }
ガベージコレクションについて
JavaScriptエンジンにはガベージコレクタと呼ばれるバックグラウンドプロセスがあります。それはすべてのオブジェクトを監視し、到達不可能になったオブジェクトを削除します。
特徴
- 自動で実行されるものであり制御はできない
- オブジェクトは淘汰る可能な間メモリ上に保持される
- 参照される != 到達可能
該当ページには、図が豊富に使用されているためわかりやすかったですでので詳しく知りたい方はぜひコチラへ!
オブジェクトメソッド
JavaScriptでは、定義した関数をあるオブジェクトのプロパティとして割り当てることが出来ます。
オブジェクトのプロパティとなっている関数は、メソッドと呼ばれます。
let user = {
name: "John",
age: 30
};
//新しいプロパティ名に関数式を用いてメソッドを割り当てる
user.sayHi = function() {
alert("Hello!");
};
user.sayHi(); // Hello!
使い方も先ほど学習したプロパティと同様に使えるので覚えやすいですね!
メソッド中で使用されるthis
について
オブジェクトのメソッドが処理をするために、オブジェクトに格納されている情報にアクセスするにはthis
を用います。
そしてこのthis
はオブジェクトのメソッドだけではなく、任意の関数内で使用することができます。
ではそれぞれの使い方についてソースコードを見ていきます。
//オブジェクトのメソッドで呼び出す
let user = {
name: "John",
age: 30,
sayHi() {
// "this" は "現在のオブジェクト"
alert(this.name);
}
};
user.sayHi(); // John
//任意の関数で呼び出し
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// 2つのオブジェクトで同じ関数を使う
user.f = sayHi;
admin.f = sayHi;
// これらの呼び出しは異なる this を持ちます
// 関数の中の "this" は "ドット" の前のオブジェクトです
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
admin['f'](); // Admin (ドットでも角括弧でも問題なくメソッドにアクセスできます)
オプショナルチェイニングについて
存在しないプロパティにアクセスしようとした際にオプショナルチェイニング?.
は役に立ちます。
- 処理内容
?.
の前部分がundefind
もしくはnull
である場合検査を止め、undefind
を戻します。
let user = {}; // ユーザは address を持たない
alert( user?.address?.street ); // undefined
シンボル型について
オブジェクトのプロパティのキーは文字列型、もしくはシンボル型のいずれかとなっており、このシンボル値はそのオブジェクト固有の識別子を表しています。
let id1 = Symbol("id");
let id2 = Symbol("id");
alert(id1 == id2); // false
//ここから一意に定まる値であることが確かめられている
また、オブジェクトリテラルの中でシンボルを利用する場合[ ]
で囲う必要があります。
let id = Symbol("id");
let user = {
name: "John",
[id]: 123 // 単に "id: 123" ではありません
};
そして、プロパティをすべて表示するfor inでは表示されないため、直接入力する必要があります。
let id = Symbol("id");
let user = {
name: "John",
age: 30,
[id]: 123
};
for (let key in user) alert(key); // name, age (no symbols)
// symbol による直アクセスは動作します
alert( "Direct: " + user[id] );
グローバルシンボル
グローバルシンボルレジストリを利用することで同じ名前のシンボルを同じエンティティにすることが出来ます。
レジストリからシンボルを読み取るためには、Symbol.for(key)
を使います。
(ない場合は作成する)
早速ソースコードを見ていきましょう
// グローバルレジストリから読む
let id = Symbol.for("id"); // symbol が存在しない場合、作られます
// 再度読み込み
let idAgain = Symbol.for("id");
// 同じシンボル
alert( id === idAgain ); // true
Symbol.keyFor
Symbol.keyFor(sym)
では、グローバルシンボルを元に、名前を返します。
さっきと逆のことをするだけなので見た方が早いと思います。
// 名前 から シンボルを取得
let sym = Symbol.for("name");
let sym2 = Symbol.for("id");
// symbol から名前を取得
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id
どこで使うんだろう...
さいごに
本記事ではオブジェクト型とシンボル型の2つのデータ型について述べました。
フロントに触れた日にちが浅く、オブジェクト型についてはそこそこ理解できたつもりではいますが、シンボル型については、まだ使いどころを思い浮かべることが出来ませんでした。
しかしJavaScriptは、フロントを開発を行う上で最低限必要な言語だと感じていますのでまだまだ継続的に学んだことを記事にまとめていけたらなと思います!