[メモ] JavaScript プロトタイプとクラスを学んでTodoリストを作った

ミス等有りましたらご助言いただけますと幸いです。
#コンストラクタ
オブジェクトを生成するには、 `{}`のようなオブジェクト初期化子を使用するか、コンストラクタ関数を用いる。
コンストラクタ関数はオブジェクトの雛形(種類)を定義する。
定義したら、new を用いてそのオブジェクトのインスタンスを作成する。

```js:app
function Task(name) {
  this.name = name;
  this.isDone = false;
}
const task = new Task('a');
```

[参考](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Creating_New_Objects/Using_a_Constructor_Function)

#プロトタイプ
オブジェクトは`prototype`オブジェクトという特別なプロパティを持っている。
コンストラクタ関数と併せて使用し、インスタンス化した際に`__proto__`に`prototype`の参照がコピーされる。

```js:app.js
// ES6以前
function Task(name) {
  this.name = name;
  this.isDone = false;
}

Task.prototype.alertName = function(){
  alert(this.name);
};

const task = new Task('a');
task.alertName();
```
prototypeを使って既存のコンストラクタにメソッドを追加でき、インスタンス化したオブジェクトから呼び出すことが可能。

下記のように、メソッドを定義しないのはメモリの節約(インスタンス化するたびに定義される)のため。

```js:app.js
function Task(name) {
  this.name = name;
  this.isDone = false;
  this.alertName = function() { ~~ };
}
```

#プロトタイプチェーン
どのオブジェクトもプロトタイプと呼ばれる、他のオブジェクトへの内部的な繋がりを持っている。
そのプロトタイプオブジェクトもプロトタイプを持っており、あるオブジェクトのプロトタイプが null に到達するまでそれが続く。
つまり、プロトタイプが多階層になっていること。

![スクリーンショット 2020-11-01 22.44.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174757/09510f0f-f913-4333-bee7-a61b4154c91f.png)

例えば、下記を実行する。

```js:app.js
const task = new Task('a');
task.hasOwnProperty('name');
```

`hasOwnProperty`というメソッドは、`Task`オブジェクトは持っていないし、プロトタイプに定義もしていないので、
更に下のprototype オブジェクト (Objectのprototype) の`hasOwnProperty`を実行する。

![スクリーンショット 2020-11-01 23.12.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174757/3f420cb2-734f-bce4-6b58-0bd54e1d2e0c.png)

優先順位は、コンストラクタ内に定義したものが一番最初、次にプロトタイプ、次にプロトタイプのプロトタイプ...となる

>1. プロパティの値がローカルに存在するかを確かめ、存在している場合は、その値を返します。
>2. 値がローカルに存在していない場合は、プロトタイプチェーンを確認します（__proto__ プロパティを使用）。
>3. プロトタイプチェーン内のオブジェクトが指定したプロパティの値を持っている場合は、その値を返します。
>4. そのようなプロパティが見つからない場合は、オブジェクトにそのプロパティは存在しません。


[参考](https://developer.mozilla.org/ja/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)

#プロトタイプを使った継承
プロトタイプチェーンを使って、プロトタイプオブジェクトを下ってプロパティを使用できることがわかったので、これを用いて継承をしていく。

タスクオブジェクトのもととなるコンストラクタ関数を下記のように定義する。

```js:app
function Task(name) {
  this.name = name;
  this.isDone = false;
}
Task.prototype.alertName = function() { alert(this.name); };
```

これを継承し、期限を設定できるタスクを作成したい。ついでにそれをアラートするメソッドも
まずは、同様に作成してみる。

```js:app
function LimitTask(name, limit) {
  this.name = name;
  this.isDone = false;
  this.limit = limit;
}
LimitTask.prototype.alertName = function() { alert(this.name); };
LimitTask.prototype.alertLimit = function() { alert(this.limit); };
```

上記は下記の様に置き換えることができます

```js:app
function LimitTask(name, limit) {
  Task.call(this, name);
  this.limit = limit;
}
LimitTask.prototype  = Object.create(Task.prototype);
LimitTask.prototype.alertName = function() { alert(this.name); };
```

call() はオブジェクトに所属する関数やメソッドを、別なオブジェクトに割り当てて呼び出すことができます。第一引数は、呼び出されたときに this として使用される値です。

LimitTaskの`this`がTaskの`this`としても使われるので、Taskのほうで`this.name`とやったら、`this`が指しているオブジェクトは同じなので、LimitTaskに`name`プロパティができる

あとは、`LimitTask`のプロトタイプに`Task`のプロトタイプオブジェクトを追加してやります。
そうすると、プロトタイプチェーンのおかげで使用できます。

```js:app.js
const limitTask = new LimitTask('やばいタスク', 'あした');
limitTask.alertName();
limitTask.alertLimit();
```

#クラス
ES6で登場した、上記で今まで記したもののシンタックスシュガー(糖衣構文)として`class`を用いることができます。

>糖衣構文: 複雑でわかりにくい書き方と全く同じ意味になるものを、よりシンプルでわかりやすい書き方で書くことができるもの

classを使い、同様にコンストラクタ関数を定義してみます。

```js:app.js
class Task
  constructor (name) {
    this.name = name;
    this.isDone = false;
  }
}
```

メソッドを実装してみます

```js:app.js
class Task
  constructor (name) {
    this.name = name;
    this.isDone = false;
  }
  alertName() {
    alert(this.name);
  }
}
```

継承してみます

```js:app.js
class LimitTask extends Task
  constructor (name, limit) {
    super(name);
    this.limit = limit;
  }
  alertLimit() {
    alert(this.limit);
  }
}
```

`super();`で基底のオブジェクトのコンストラクタを呼び出しています。

他にもgetter setterや静的メソッドもあります。

[詳しくはこちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes)

#おわりに
とりあえず、アウトプットに簡易Todoリストを作ってみた。
いまいち感がすごいのでよりよい方法有りましたらご助言いただけますと幸いです。

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="js,result" data-user="natsume0718" data-slug-hash="ZEOxaYE" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="OOP ToDo">
  <span>See the Pen <a href="https://codepen.io/natsume0718/pen/ZEOxaYE">
  OOP ToDo</a> by natusme (<a href="https://codepen.io/natsume0718">@natsume0718</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>