JavaScript入門 #オブジェクト型とシンボル型

## はじめに

本記事では、JavaScriptにおけるデータ型の[オブジェクト型](#オブジェクトとは)と[シンボル型](#シンボル型について)について周辺知識をまとめていきます。

今回の記事も[以前書いた記事][記事]と同様に以下のサイトのチュートリアルを進める中で学んだことをまとめていますのでJavaScriptを勉強している、してみたい方は是非参考にしてください！

https://ja.javascript.info/

## オブジェクトとは

早速本題である「オブジェクト」について説明していきたいと思います。

オブジェクトとは、キー付けされた様々なデータのコレクションや、より複雑なエンティティを格納するために使用されます。

- オブジェクトのきほん

波カッコと任意のプロパティから成り立ち、プロパティは “キー:値” のペアで、キーは文字列であり、値に制限はありません。

～記述例～

```javascript:空のオブジェクト
let user = new Object(); // "オブジェクトコンストラクタ" 構文
let user = {};  // "オブジェクトリテラル" 構文
//どちらの記述方法でも構いません。
```

```javascript:オブジェクトの宣言
let user = {     // オブジェクト
  name: "John",  // キー "name" に値 "John" が格納される
  age: 30        // キー "age" に値 30 が格納される
};
//この時のプロパティ数は２
```

### プロパティの参照

初期化してあるオブジェクトのプロパティは以下のようにして参照します。

```javascript:プロパティの参照
//オブジェクト名.プロパティ名
//例
alert( user.name ); // John
```

### プロパティの追加

また、プロパティの追加を行うことが出来ます。

```javascript:プロパティの参照
//オブジェクト名.追加したいプロパティ名 = 値
//例
user.isAdmin = true;
```

### プロパティの削除

プロパティの削除には、`delete`演算子を用います

```javascript:プロパティの削除
//delete オブジェクト名.プロパティ名
//例
delete user.age;
```

### 空白を含むプロパティ名

空白を含むプロパティに対して`.`（ドット）を用いてアクセスしようとするとエラーになります。そんな時に登場するのが`[ ]`を用いたアクセスです。

早速使い方を見てみましょう

```javascript:[ ]を用いたアクセス
let user = {};

// set
user["likes birds"] = true;

// get
alert(user["likes birds"]); // true

// delete
delete user["likes birds"];
```
これで問題なく空白を含んだプロパティにもアクセスすることが出来ます。

- 使用制限

`.`：スペースが含まれていない、数値から始まっていない、特殊文字が含まれていないなど

`[ ]`：任意の文字列で動作

という風に`[ ]`でアクセスする方がプロパティ名に対して柔軟に対応することが出来ます。

> それでも[予約語][予約語]は用いることが出来ないことに注意してください。

### `in`演算子について

JavaScript では、どんなプロパティへもアクセスでき、プロパティが存在しない場合でもエラーにはならず、`undefind`を返します。

ここでプロパティが存在するかどうかを確かめる`in`演算子というものがあります。


```javascript:in演算子の使い方
let user = { name: "John", age: 30 };

//プロパティ名 in オブジェクト名
alert( "age" in user ); // true, user.age は存在する
alert( "blabla" in user ); // false, user.blabla は存在しない
```

### ～応用編～すべてのプロパティを確認する

オブジェクトの全てのプロパティを確認するにはfor文を用います。

```javascript:全てのプロパティの参照
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`関数を用います。

最初に関数の使い方を紹介します。

```javascript:Object.assign関数使い方
Object.assign(複製先オブジェクト名[複製するプロパティ名, src1, src2...])
```

次に変数の複製を作成するソースコードを見ていきましょう。

```javascript:空のコンストラクタを使用
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
```

```javascript:Object.assign関数使用例
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では、定義した関数をあるオブジェクトのプロパティとして割り当てることが出来ます。

オブジェクトのプロパティとなっている関数は、メソッドと呼ばれます。

```javascript:メソッドの割り当て
let user = {
  name: "John",
  age: 30
};

//新しいプロパティ名に関数式を用いてメソッドを割り当てる
user.sayHi = function() {
  alert("Hello!");
};

user.sayHi(); // Hello!
```

使い方も先ほど学習したプロパティと同様に使えるので覚えやすいですね！

### メソッド中で使用される`this`について

オブジェクトのメソッドが処理をするために、オブジェクトに格納されている情報にアクセスするには`this`を用います。

そしてこの`this`はオブジェクトのメソッドだけではなく、任意の関数内で使用することができます。

ではそれぞれの使い方についてソースコードを見ていきます。

```javascript: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`を戻します。

```javascript:?.の使い方
let user = {}; // ユーザは address を持たない
alert( user?.address?.street ); // undefined 
```

## シンボル型について

オブジェクトのプロパティのキーは文字列型、もしくはシンボル型のいずれかとなっており、このシンボル値はそのオブジェクト固有の識別子を表しています。

```javascript:シンボル値の作成
let id1 = Symbol("id");
let id2 = Symbol("id");

alert(id1 == id2); // false
//ここから一意に定まる値であることが確かめられている
```

また、オブジェクトリテラルの中でシンボルを利用する場合`[ ]`で囲う必要があります。

```javascript:リテラルの中でシンボルの利用
let id = Symbol("id");

let user = {
  name: "John",
  [id]: 123 // 単に "id: 123" ではありません
};
```

そして、プロパティをすべて表示するfor inでは表示されないため、直接入力する必要があります。

```javascript:プロパティの表示方法
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)`を使います。
（ない場合は作成する）

早速ソースコードを見ていきましょう

```javascript:グローバルシンボル利用例
// グローバルレジストリから読む
let id = Symbol.for("id"); // symbol が存在しない場合、作られます

// 再度読み込み
let idAgain = Symbol.for("id");

// 同じシンボル
alert( id === idAgain ); // true
```

### Symbol.keyFor

`Symbol.keyFor(sym)`では、グローバルシンボルを元に、名前を返します。

さっきと逆のことをするだけなので見た方が早いと思います。

```javascript:逆引き
// 名前 から シンボルを取得
let sym = Symbol.for("name");
let sym2 = Symbol.for("id");

// symbol から名前を取得
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id
```

> どこで使うんだろう...

## さいごに

本記事ではオブジェクト型とシンボル型の２つのデータ型について述べました。

フロントに触れた日にちが浅く、オブジェクト型についてはそこそこ理解できたつもりではいますが、シンボル型については、まだ使いどころを思い浮かべることが出来ませんでした。

しかしJavaScriptは、フロントを開発を行う上で最低限必要な言語だと感じていますのでまだまだ継続的に学んだことを記事にまとめていけたらなと思います！


[記事]: https://qiita.com/masamasamasami/items/d26d14ae674a57011948
[予約語]: https://www.javadrive.jp/javascript/ini/index5.html
[サイト]: https://ja.javascript.info/garbage-collection