#オブジェクト指向とは
- オブジェクト指向はオブジェクトリテラルとClassの2通り作る方法があります
#オブジェクトリテラル
下記のようにキーと値の組み合わせがある、オブジェクトの型を定義する記法です。
const n =
{
name: {
Name1: 'Petter',
Name2: 'Quil'
},
age: 38,
gender: 'male'
}
#Classのインスタンス
- インスタンス
new クラス名()
で作成することができます。
インスタンスとはPersonクラスを元にして、 new を呼び出して作ったPersonオブジェクトです。
つまり、インスタンスはクラスからできたオブジェクト
ということです。
- constructor
インスタンスが作成された時にconstructor
が実行されます。
constructorはインスタンスが作成されたときに実行されるので、new Person('Quill')
のQuillがconstructor(initName: string)
のinitNameに入ります。
initNameを持つthis.name
ですが、thisをつけることでPersonクラスのnameプロパティにアクセスでき、nameにinitNameの値が入ります。
console.log(quill);
で最終的に'Quill'
と表示されます。
class Person {
name: string;//プロパティ(値)
constructor(initName: string){//最初の処理
this.name = initName;
}
}
const quill = new Person('Quill');//インスタンス作成(Personオブジェクト)
console.log(quill);
#classのメソッド
メソッドはクラス内に書くことができます。
const quill = new Person('Quill');
でconstructor経由でnameには'Quill'が入っており、quill.greeting();
でgreetingメソッドが呼び出されます。greetingメソッド内のthis.nameはクラス内のnameを示すので、quill.greeting();
では``Hello My name is Quill`と表示されます。
class Person {
name: string;
constructor(initName: string){
this.name = initName;
}
greeting() {
console.log(`Hello My name is ${this.name}`);
}
}
const quill = new Person('Quill');
quill.greeting();
では次は新しく追加したanotherQuillオブジェクトでのthisの挙動を見てみましょう。
quill.greeting();
ではHello My name is Quill
を示しますが、新規に作成したオブジェクトでanotherQuill.anotherGreeting();
を実行するとHello My name is undefined
になってしまいます。
クラスを用いずにオブジェクトを作った場合、greetingメソッドのthisはanotherQuillを示すので、anotherQuill内でnameを指定しないとundefinedとなってしまいます。
class Person {
name: string;
constructor(initName: string){
this.name = initName;
}
greeting() {
console.log(`Hello My name is ${this.name}`);
}
}
const quill = new Person('Quill');
quill.greeting();
//クラスを用いずにオブジェクトを作った場合、greetingメソッドのthisはanotherQuillを示すので、anotherQuill内でnameを指定しないとundefinedになる
const anotherQuill = {
anotherGreeting: quill.greeting
}
anotherQuill.anotherGreeting();
anotherQuill内でnameを定義するとgreetingメソッドのthisはanotherQuillオブジェクト内のnameを参照できるので、Hello My name is anotherQuill
となります。
thisは定義されたときでなく、呼び出されたときに決まります。
なので、quill.greeting();
の時点ではgreetingのthisはPerson内でのnameを示し、anotherQuill
ではanotherQuill内でのnameを示します。
const anotherQuill = {
name: 'anotherQuill',
anotherGreeting: quill.greeting
}
anotherQuill.anotherGreeting();
因みにですが、下記のようにanotherQuillにnameを指定しなくてもエラ-は起きません。何故なら、typescriptはquill.greetingのgreetingメソッドのthisがどこで使われてるかまでは見ないからです。
greeting() {
console.log(`Hello My name is ${this.name}`);
}
const anotherQuill = {
anotherGreeting: quill.greeting
}
anotherQuill.anotherGreeting();
しかし、下記のようにgreetingメソッドにthisを追記するとanotherQuill.anotherGreeting();のanotherQuillがエラーになります。これはgreetingメソッドにthisを追記することでanotherGreeting: quill.greetingのthisがどれを指してるのかtypescriptが理解できるからです。
エラーの原因はanotherQuillにnameが無いことなのでnameを指定する必要があります。
//引数にthisをつけることでメソッドが呼び出された時にthisの内容を伝えれる
greeting(this: {name: string}) {
console.log(`Hello My name is ${this.name}`);
}
const anotherQuill = {
anotherGreeting: quill.greeting
}
anotherQuill.anotherGreeting();
anotherQuillにname: 'anotherQuill'
を指定することでエラーは解消されます。
const anotherQuill = {
name: 'anotherQuill',
anotherGreeting: quill.greeting
}
anotherQuill.anotherGreeting();
- アロー関数
アロー関数にすることで、通常の関数のthisは呼び出し時に決まるが、アロー関数だと定義時にthisが決まるので今回だと'Quill'が出続ける
greeting() => {
console.log(`Hello My name is ${this.name}`);
}
#クラスを型として使う
this: Person
とすることでクラスを型として使えます。let person2: Person;
とすることでprson2はnemeとgreetingメソッドを持つオブジェクトになります。
class Person {
name: string;
constructor(initName: string){
this.name = initName;
}
greeting(this: Person) {
console.log(`Hello My name is ${this.name}`);
}
}
let person2: Person;
anotherQuillは下記のようになります。quill.greetingのgreetingのthisはnameとgreetingメソッドを示しているのでgreeting() {}
を追記する必要があります。
Personを再現しないと使えないようにすることでエラーを防ぐことができます。
const anotherQuill = {
name: 'anotherQuill',
greeting() {},
anotherGreeting: quill.greeting
}
anotherQuill.anotherGreeting();