📝

JavaScript 学習実施メモ 3

2021/02/08に公開

初学者のメモです。間違い等ありましたらご指摘コメント待ってます。

三個目です。

前回: https://zenn.dev/yuki_kanayama/articles/bc6feb6c0ec64f

初回: https://zenn.dev/yuki_kanayama/articles/37022f0373e38d

コンストラクター関数

新しくオブジェクトを作成するための雛形となる関数。呼び出し方法が特殊で、

1. function A() {
2.   this.prop = 0;
3. }
4.  
5. const hoge = new A();

newを使いオブジェクトを作成することをインスタンス化といい、作成されたオブジェクトをインスタンスという。

コンストラクター関数を利用することで、オブジェクトの雛形を基準に作成することができる。

1. function Person(name, age) {
2.   this.name = name;
3.   this.age = age;
4. }
5.  
6. const bob = new Person('Bob', 23);
7. const james = new Person('James', 26);
8. const aria = new Person('Aria', 33);

上記のように定義すること

1. bob
2.     Person {name: "Bob", age: 23}
3.  
4. james
5.     Person {name: "James", age: 26}
6.  
7. aria
8.     Person {name: "Aria", age: 33}

3つのオブジェクトを作成することができる。

プロトタイプ

オブジェクトに存在する特別なプロパティ。コンストラクタ関数と合わせて使用する。

1. function Person(name, age) {
2.     this.name = name;
3.     this.age = age;
4. }
5.  
6. Person.prototype.hello = function() {
7.     console.log('hello ' + this.name);
8. }
9.  
10. const bob = new Person('Bob', 18);
11.  
12. bob.hello(); // hello Bob

上記のように、コンストラクタ関数のプロパティとして定義することで、インスタンス化した時にインスタンスに prototype の参照がコピーされる。

1. function Person(name, age) {
2.     this.name = name;
3.     this.age = age;
4.     this.hello = function() {
5.         console.log('hello ' + this.name);
6.     }
7. }

また、このように記述してもhelloというメソッドを作成でき、インスタンス側で使用できるがこの場合だと各インスタンスにメソッドができるためパフォーマンスが悪くなる可能性がある。プロトタイプだと参照がコピーされているだけなので、メソッド自体が増えているわけではない。

new演算子

コンストラクター関数からインスタンスを作成するために使用する演算子。

1. function F(a, b) {
2.     this.a = a;
3.     this.b = b;
4.     return {a: 10};
5. }
6.  
7. F.prototype.c = function() {}
8.  
9. function newOpe(C, ...args) { // new演算子
10.     const _this = Object.create(C.prototype);
11.     const result = C.apply(_this, args);
12.  
13.     if(typeof result === "object" && result !== null) {
14.         return result;
15.     }
16.     return _this;
17. }
18.  
19. const instance = newOpe(F, 1, 2);

内部ではこのようにうごている。コンストラクタ関数(上記の関数newOpeのCの部分)の戻り値がオブジェクトの場合(if分の部分)そのオブジェクトを新しいインスタンスオブジェクトとして作成する。上記の場合は{ a: 10 }が作成される。(prototypeは新しく生成されたものがある。)

オブジェクト以外の場合は、コンストラクタ関数のprototypeを__proto__にコピーして新しくオブジェクトを作成し、コンストラクタ関数内で定義されているthisの参照先を新しくできたオブジェクトとしてコンストラクタ関数を実行する。

instanceof

どのコンストタクター関数から生成されたオブジェクト(インスタンス)かを確認するもの。

内部では、

prototypeの参照先が同じかどうかを判別している

ので、コンストラクタ関数がオブジェクトを返している場合は、faleseとなる。

プロトタイプチェーン

プロトタイプの多重形成をのこと。

メソッドが呼ばれた場合、インスタンス自身のプロパティに該当のメソッドがあるか確認し、ない場合はコンストラクタ関数のprototypeに該当のメソッドを探しに行く。そこでもない場合は、Objectのprototypeに探しに行く。最後までなかった場合は見つかりませんエラーとなる。

hasOwnPropertyとin

1. function Person(name, age) {
2.   this.name = name;
3.   this.age = age;
4. }
5.  
6. Object.prototype.hello = function() {
7.   console.log('Object: hello ' + this.name);
8. }
9.  
10. const bob = new Person('Bob', 18);
11. const result = bob.hasOwnProperty('hello')
12. console.log(result) // false
13. console.log('hello' in bob); // true

hasOwnProperty

Objectのプロトタイプに格納されているメソッド。自身に該当プロパティが格納されているかを判別する。上記の場合だと、Objectコンストラクタ内に helloメソッドが生成されているので、bobインスタンスを判別させると false となる。

in

該当のメソッドがオブジェクト、または保持している proto に格納されているかを判別する。

プロトタイプ継承

継承

別のコンストラクタ関数を受け継ぐこと。

プロトタイプ継承

別のコンストラクタ関数のプロトタイプを受け継いで、機能を流用できるようにすること。

1. function Person(name, age) {
2.   this.name = name;
3.   this.age = age;
4. }
5.  
6. Person.prototype.hello = function() {
7.   console.log('hello ' + this.name);
8. }
9.  
10. function Japanese(nameJ, ageJ) {
11.   Person.call(this, nameJ , ageJ); // 継承
12. }
13.  
14. Japanese.prototype = Object.create(Person.prototype); //プロトタイプ継承
15.  
16. const taro = new Japanese('Taro', 26);

ちなみに、継承の部分の引数 this は Japanese の関数コンテキストを Person に渡して this.name と this.age が設定される。

クラス

コンストラクター関数をクラス表記でかけるようにしたもの。(もともとある記述方法を簡単にできるようにしたものをシンタックスシュガーという)

1. // 元の記述方法
2. // function Person(name, age) {
3. //   this.name = name;
4. //   this.age = age;
5. // }
6.  
7. // Person.prototype.hello = function() {
8. //   console.log('hello ' + this.name);
9. // }
10.  
11.  
12. // クラス表記
13. class Person {
14.   constructor(name, age) {
15.     this.name = name;
16.     this.age = age;
17.     this.bye = () => console.log('Bye ' + name);
18.   }
19.  
20.   hello() {
21.     console.log('Hello ' + this.name);
22.   }
23. }
24.  
25. const bob = new Person('Bob', 23);
26. bob.hello(); // Hello Bob
27. bob.bye(); // Bye Bob

クラス継承

他のクラスのプロパティとメソッドを継承すること。

1. class Person {
2.   constructor(name, age) {
3.     this.name = name;
4.     this.age = age;
5.   }
6.   
7.   hello() {
8.     console.log('hello ' + this.name);
9.   }
10. }
11.  
12. class Japanese extends Person { // クラス継承
13.   constructor(nameJ, ageJ, gender) {
14.     super(nameJ, ageJ)
15.     this.gender = gender;
16.   }
17.   hello() {
18.     console.log('Konnichiwa ' + this.name);
19.   }
20.   
21.   bye() {
22.     console.log('Sayonara ' + this.name);
23.   }
24. }
25.  
26. const taro = new Japanese('Taro', 23, 'Male');

継承するクラスに exetends関数  を用いて継承されるクラスを記述することで継承することができる。その際に、 constructor に super を記述する。super を実行すると継承されるクラスの constructor が実行される。

super

継承元の関数を呼び出すもの。

コンストラクタだけではなくメソッドも呼び出すことができる。

ビルドインオブジェクト

コード実行前にJSエンジンによって自動的に生成されるオブジェクト。

Discussion