6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2022年1月24日 JavaScript (JS Primer)静的メソッドの継承

【復習-1】

// プロパティを持たない空のオブジェクトを作成
// = `Object`からインスタンスオブジェクトを作成
const obj = new Object();
console.log(obj); // => {}

// 上記と以下は同義です。
const obj = {}

【復習2】 静的メソッド

静的メソッドはクラスをインスタンス化せずに利用できます。

class クラス {
    static メソッド() {
        // 静的メソッドの処理
    }
}
// 静的メソッドの呼び出し
クラス.メソッド();

静的メソッドの継承

継承を行うと、静的メソッドも継承されます。

class Parent {
    static hello() {
        return "Hello";
    }
}
class Child extends Parent {}
console.log(Child.hello()); // => "Hello"

extendsによって継承した場合、子クラスのコンストラクタのPrototype内部プロパティには親クラスのコンストラクタが設定されます。 このコードでは、ChildコンストラクタのPrototype内部プロパティにParentコンストラクタが設定されます。

Child.helloプロパティを参照した場合には、次のような順番でオブジェクトを探索しています。

1. Childコンストラク
2. Parentコンストラクタ(ChildコンストラクタのPrototypeの参照先)

クラスのコンストラクタ同士にもプロトタイプチェーンの仕組みがあるため、子クラスは親クラスの静的メソッドを呼び出せます。

ここで確認をしてみます。

class Parent {
    static hello() {
        return "Hello";
    }
}
class Child extends Parent {}
const yano = new Child();
console.log(yano);

上記のように定義したインスタンスオブジェクトを出力してみると以下のようになります。

superプロパティ

子クラスから親クラスのコンストラクタ処理を呼び出すにはsuper()を使います。 同じように、子クラスのプロトタイプメソッドからは、super.プロパティ名で親クラスのプロトタイプメソッドを参照できます。

次のコードでは、Child#methodの中でsuper.method()と書くことでParent#methodを呼び出しています。 このように、子クラスから継承元の親クラスのプロトタイプメソッドはsuper.プロパティ名で参照できます。

class Parent {
    method() {
        console.log("Parent#method");
    }
}
class Child extends Parent {
    method() {
        console.log("Child#method");
        // `this.method()`だと自分(`this`)のmethodを呼び出して無限ループする
        // そのため明示的に`super.method()`とParent#methodを呼び出す
        super.method();
    }
}
const child = new Child();
child.method();
// コンソールには次のように出力される
// "Child#method"
// "Parent#method"

Child#methodはChild.prototype.methodと同じ意味でしたね。

このコードではChild#methodが定義されているため、child.methodはChild#methodを呼び出します。 そしてChild#methodはsuper.methodを呼び出しているため、Parent#methodが呼び出されます。

静的メソッドの例

クラスの静的メソッド同士も同じようにsuper.method()と書くことで呼び出せます。 次のコードでは、Parentを継承したChildから親クラスの静的メソッドを呼び出しています。

class Parent {
    static method() {
        console.log("Parent.method");
    }
}
class Child extends Parent {
    static method() {
        console.log("Child.method");
        // `super.method()`で`Parent.method`を呼びだす
        super.method();
    }
}
Child.method();
// コンソールには次のように出力される
// "Child.method"
// "Parent.method"

継承の判定

あるクラスが指定したクラスをプロトタイプ継承しているかはinstanceof演算子を使って判定できます。

次のコードでは、ChildのインスタンスはChildクラスとParentクラスを継承したオブジェクトであることを確認しています。

class Parent {}
class Child extends Parent {}

const parent = new Parent();
const child = new Child();
// `Parent`のインスタンスは`Parent`のみを継承したインスタンス
console.log(parent instanceof Parent); // => true
console.log(parent instanceof Child); // => false
// `Child`のインスタンスは`Child`と`Parent`を継承したインスタンス
console.log(child instanceof Parent); // => true
console.log(child instanceof Child); // => true

上記のコードを日本語で言い換えると以下のようになります。

親クラスを継承した子クラス"child"の場合

親クラスで定義したものを継承した子クラスから呼び出すことは可能だという認識を持ちました。 その方法や仕組みについて学べました。

参考

JS primer 静的メソッドの継承

2022年1月22日 JavaScript (JS Primer) プロトタイプ継承

子クラスのインスタンスから親クラスのプロトタイプメソッドを呼び出す例を学習しました。

プロトタイプ継承

Parentクラスではmethodを定義しているため、これを継承しているChildクラスのインスタンスからも呼び出せます。

class Parent {
    method() {
        console.log("Parent#method");
    }
}
// `Parent`を継承した`Child`を定義
class Child extends Parent {
    // methodの定義はない
}
const instance = new Child();
instance.method(); // "Parent#method"

このように、子クラスのインスタンスから親クラスのプロトタイプメソッドもプロトタイプチェーンの仕組みによって呼び出せます。

extendsによって継承した場合、子クラスのプロトタイプオブジェクトのPrototype内部プロパティには親クラスのプロトタイプオブジェクトが設定されます。 このコードでは、Child.prototypeオブジェクトのPrototype内部プロパティにはParent.prototypeが設定されます。

プロパティを参照する場合のオブジェクトを探索する順番

1、instanceオブジェクト自身

2、Child.prototype(instanceオブジェクトのPrototypeの参照先)

3、Parent.prototype(Child.prototypeオブジェクトのPrototypeの参照先)

このプロトタイプチェーンの仕組みにより、methodプロパティはParent.prototypeオブジェクトに定義されたものを参照します。

このようにJavaScriptではclass構文とextendsキーワードを使うことでクラスの機能を継承できます。 class構文ではプロトタイプオブジェクトを参照する仕組みによって継承が行われています。 そのため、この継承の仕組みをプロトタイプ継承と呼びます。

親クラスを継承した子クラスのインスタンスを出力してみました。

以下のコードを出力してみます。

class Parent {
    methood() {
        console.log("Parent#method");
    }
}
class Child extends Parent {
}
const instance = new Child();
instance.methood(); // "Parent#method"
console.log(instance);

コメント

説明を読んだ上でインスタンスの中身を見てみると改めて勉強になりました。

参考

JS primer プロトタイプ継承

2022年1月21日 JavaScript (JS Primer) 継承

本日はクラスの継承について勉強しました。

継承

extendsキーワードを使うことで既存のクラスの構造や機能を引き継いだ新しいクラスを定義することが出来ます。

クラスの定義

以下のように定義します。

class 子クラス extends 親クラス {
    ~子クラスの定義~
}

Rubyの場合は以下のようになります。

class クラス名 < 継承したいクラス名
end

super

extendsを使って定義した子クラスから親クラスを参照するにはsuperというキーワードを利用します。

クラスは必ずconstructorメソッド(コンストラクタ)を持ちます。 これは、継承した子クラスでも同じです。

次のコードでは、Parentクラスを継承したChildクラスのコンストラクタで、super()を呼び出しています。 super()は子クラスから親クラスのconstructorメソッドを呼び出します。

// 親クラス
class Parent {
    constructor(...args) {
        console.log("Parentコンストラクタの処理", ...args);
    }
}
// Parentを継承したChildクラスの定義
class Child extends Parent {
    constructor(...args) {
        // Parentのコンストラクタ処理を呼び出す
        super(...args);
        console.log("Childコンストラクタの処理", ...args);
    }
}
const child = new Child("引数1", "引数2");
// "Parentコンストラクタの処理", "引数1", "引数2"
// "Childコンストラクタの処理", "引数1", "引数2"

class構文でのクラス定義では、constructorメソッド(コンストラクタ)で何も処理しない場合は省略できることを紹介しました。 これは、継承した子クラスでも同じです。

次のコードのChildクラスのコンストラクタでは、何も処理を行っていません。 そのため、Childクラスのconstructorメソッドの定義を省略できます。

class Parent {}
class Child extends Parent {}

このように子クラスでconstructorを省略した場合は次のように書いた場合と同じ意味になります。 constructorメソッドの引数をすべて受け取り、そのままsuperへ引数の順番を維持して渡します。

class Parent {}
class Child extends Parent {
    constructor(...args) {
        super(...args); // 親クラスに引数をそのまま渡す
    }
}

復習

  • Rest parametersは、仮引数名の前に...をつけた仮引数のことで、残余引数とも呼ばれます。 Rest parametersには、関数に渡された値が配列として代入されます。

  • Spread構文は関数を呼び出す際に使用します。配列やオブジェクトを展開することができます。

const array = [1, 2, 3];
// Spread構文で配列を引数に展開して関数を呼び出す
fn(...array);
// 次のように書いたのと同じ意味
fn(array[0], array[1], array[2]);

console.log(...array); // => 1, 2, 3

コンストラクタの処理順は親クラスから子クラスへ

コンストラクタの処理順は、親クラスから子クラスへと順番が決まっています。

class構文では必ず親クラスのコンストラクタ処理(super()の呼び出し)を先に行い、その次に子クラスのコンストラクタ処理を行います。 子クラスのコンストラクタでは、thisを触る前にsuper()で親クラスのコンストラクタ処理を呼び出さないとReferenceErrorとなるためです。

次のコードでは、ParentとChildでそれぞれインスタンス(this)のnameプロパティに値を書き込んでいます。 子クラスでは先にsuper()を呼び出してからでないとthisを参照できません。 そのため、コンストラクタの処理順はParentからChildという順番に限定されます

class Parent {
    constructor() {
        this.name = "Parent";
    }
}
class Child extends Parent {
    constructor() {
        // 子クラスでは`super()`を`this`に触る前に呼び出さなければならない
        super();
        // 子クラスのコンストラクタ処理
        // 親クラスで書き込まれた`name`は上書きされる
        this.name = "Child";
    }
}
const parent = new Parent();
console.log(parent.name); // => "Parent"
const child = new Child();
console.log(child.name); // => "Child"
  • 仮にsuper();の前に子クラスの別の処理を書いた場合は、以下のエラーが発生します。

    ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
    英訳: ReferenceError: this' にアクセスする前、または派生クラスのコンストラクタから戻る前に、派生クラスのスーパーコンストラクタを呼び出す必要があります。

継承した子クラスのコンストラクタ関数内ではsuper を使用して親クラスのコンストラクタ関数を呼び出さないとエラーになります。

コメント

今回は特に深堀りするところはなかったので、書籍の内容を理解して覚えることに重点を置いた内容になりました。

子クラスのコンストラクタに処理を書く場合は必ず親クラスのコンストラクタを呼び出す記述を先に書かないといけないということが大事だと思いました。

参考

JS primer 継承

2022年1月20日 JavaScript (JS Primer) プロパティの参照とプロトタイプチェーン

プロトタイプオブジェクトのプロパティがどのようにインスタンスから参照されるか

オブジェクトのプロパティを参照するときに、オブジェクト自身がプロパティを持っていない場合でも、そこで探索が終わるわけではありません。 オブジェクトのPrototype内部プロパティ(仕様上の内部的なプロパティ)の参照先であるプロトタイプオブジェクトに対しても探索を続けます。 これは、スコープに指定した識別子の変数がなかった場合に外側のスコープへと探索するスコープチェーンと良く似た仕組みです。

つまり、オブジェクトがプロパティを探索するときは次のような順番で、それぞれのオブジェクトを調べます。 すべてのオブジェクトにおいて見つからなかった場合の結果はundefinedを返します。

クラスのインスタンスを出力してみる

オブジェクトがプロパティを探索するときは次のような順番で調べられます。

1.instanceオブジェクト自身
2. instanceオブジェクトの[[Prototype]]の参照先(プロトタイプオブジェクト)
3.どこにもなかった場合はundefined

上記の例の元のコードは以下です。

class ConflictClass {
    constructor() {
        this.method = () => {
            console.log("インスタンスオブジェクトのメソッド");
        };
    }
    method() {
        console.log("プロトタイプメソッド");
    }
}
const conflict = new ConflictClass();
console.log(conflict);

出力結果: { method: [Function] }

instanceオブジェクト自身 instanceオブジェクトのPrototypeの参照先(プロトタイプオブジェクト) どこにもなかった場合はundefined 次のコードでは、インスタンスオブジェクト自身はmethodプロパティを持っていません。 そのため、実際に参照しているのはクラスのプロトタイプオブジェクトのmethodプロパティです。

ここを読んで感動しました。 スコープに指定した識別子の変数がなかった場合に外側のスコープへと探索するスコープチェーンと良く似た仕組みです。 私はプロトタイプチェーンという言葉に違和感を覚えていましたが、ここを読んで完全に腑に落ちました。インスタンス化した変数からメソッドを呼び出そうとした場合にまず今いるスコープからインスタンスオブジェクトのmethodを探索します。もしなかった場合にスコープチェーンの仕組みの外のスコープに探しにいく原理と同様に、prototypeに探索しにいきます。(ここでチェーンという名称の意味が繋がりました)そして、もしprototypeにもmethodがなかった場合にundefinedになります。これで同じクラス内にプロトタイプメソッドとインスタンスオブジェクトのメソッドを定義していたら、インスタンスメソッドが優先される理由も完全に理解できました。

class MyClass {
    method() {
        console.log("プロトタイプのメソッド");
    }
}
const instance = new MyClass();
// インスタンスには`method`プロパティがないため、プロトタイプオブジェクトの`method`が参照される
instance.method(); // "プロトタイプのメソッド"
// `instance.method`の参照はプロトタイプオブジェクトの`method`と一致する
const Prototype = Object.getPrototypeOf(instance);
console.log(instance.method === Prototype.method); // => true
実行

このように、インスタンスオブジェクトにmethodが定義されていなくても、クラスのプロトタイプオブジェクトのmethodを呼び出すことができます。 このプロパティを参照する際に、オブジェクト自身からPrototype内部プロパティへと順番に探す仕組みのことをプロトタイプチェーンと呼びます。

プロトタイプチェーンの仕組みを疑似的なコードとして表現すると次のような動きをしています。

// プロトタイプチェーンの動作の疑似的なコード
class MyClass {
    method() {
        console.log("プロトタイプのメソッド");
    }
}
const instance = new MyClass();
// `instance.method()`を実行する場合
// 次のような呼び出し処理が行われている
// インスタンス自身が`method`プロパティを持っている場合
if (instance.hasOwnProperty("method")) {
    instance.method();
} else {
    // インスタンスの`[[Prototype]]`の参照先(`MyClass`のプロトタイプオブジェクト)を取り出す
    const prototypeObject = Object.getPrototypeOf(instance);
    // プロトタイプオブジェクトが`method`プロパティを持っている場合
    if (prototypeObject.hasOwnProperty("method")) {
        // `this`はインスタンス自身を指定して呼び出す
        prototypeObject.method.call(instance);
    }
}

プロトタイプチェーンの仕組みによって、プロトタイプオブジェクトに定義したプロトタイプメソッドをインスタンスから呼び出せます。

普段は、プロトタイプオブジェクトやプロトタイプチェーンといった仕組みを意識する必要はありません。 class構文はこのようなプロトタイプを意識せずにクラスを利用できるように導入された構文です。 しかし、プロトタイプベースである言語のJavaScriptではクラスをこのようなプロトタイプを使って表現していることは知っておくとよいでしょう。

参考

JS primer プロパティの参照とプロトタイプチェーン

2022年1月18日 JavaScript (JS Primer) プロトタイプチェーン

復習

プロトタイプメソッドはプロトタイプオブジェクトのプロパティとして定義しています。 クラスをインスタンス化したときにプロトタイプオブジェクトのプロパティとしてメソッドが組み込まれます。

class構文で定義したプロトタイプメソッドはプロトタイプオブジェクトに定義されます。 しかし、インスタンス(オブジェクト)にはメソッドが定義されていないのに、インスタンスからクラスのプロトタイプメソッドを呼び出せます。

class MyClass {
    method() {
        console.log("プロトタイプのメソッド");
    }
}
const instance = new MyClass();
instance.method(); // "プロトタイプのメソッド"

そもそもの話ですが、インスタンスオブジェクトにメソッドを定義していないのにインスタンスからプロトタイプメソッドを定義出来るのはなぜでしょうか?

それはプロトタイプチェーンという仕組みがあるからです。

プロトタイプチェーンとは2つの処理から成り立ちます。

インスタンス作成時にPrototype内部プロパティに保存し、インスタンスからプロパティ参照するときに探索してくれます。

実際に上記で生成したインスタンスを出力して検証してみました。

class MyClass {
    method() {
        console.log("プロトタイプのメソッド");
    }
}
const instance = new MyClass();
console.log(instance); // "プロトタイプのメソッド"
出力結果: {}

instanceオブジェクトの中身です。

クラスからnew演算子によってインスタンスを作成する際に、インスタンスにはクラスのプロトタイプオブジェクトへの参照が保存されます。 このとき、インスタンスからクラスのプロトタイプオブジェクトへの参照は、インスタンスオブジェクトの[[Prototype]]という内部プロパティに保存されます。

内部プロパティはECMAScriptの仕様で定められた内部的な表現であるため、通常のプロパティのようにはアクセスできません。 Object.getPrototypeOfメソッドで[[Prototype]]内部プロパティを参照できます。

以下は引用です。内部プロパティは読み書きすることは出来ますが、あまり推奨されていないようですね。 

Object.getPrototypeOf(オブジェクト)でオブジェクトのPrototypeを読み取ることができます。
一方、Object.setPrototypeOf(オブジェクト, プロトタイプオブジェクト)でオブジェクトのPrototypeにプロトタイプオブジェクトを設定できます。 また、Prototype内部プロパティを通常のプロパティのように扱えるprotoという特殊なアクセッサプロパティが存在します。

しかし、これらのPrototype内部プロパティを直接読み書きすることは通常の用途では行いません。 また、既存のビルトインオブジェクトの動作なども変更できるため、不用意に扱うべきではないでしょう。

インスタンスオブジェクトに定義したメソッドとプロトタイプメソッドを確認

class ConflictClass {
    constructor() {
        this.method = () => {
            console.log("インスタンスオブジェクトのメソッド");
        };
    }
    method() {
        console.log("プロトタイプメソッド");
    }
}
const conflict = new ConflictClass();
console.log(conflict);

出力結果: { method: [Function] }

インスタンスからプロトタイプメソッドが呼び出せるのは上の画像の[[Prototype]]method: f method() と保存されていて、こちらを探索しています。これがプロトタイプチェーンという仕組みです。

参考

JavaScript (JS Primer) プロトタイプチェーン

2022年1月17日 JavaScript (JS Primer) プロトタイプオブジェクト

前提(prototypeオブジェクトについて)

  • 正確には、ほとんどすべてのオブジェクトはObject.prototypeプロパティに定義されたprototypeオブジェクトを継承しています。
  • prototypeオブジェクトとは、すべてのオブジェクトの作成時に自動的に追加される特殊なオブジェクトです。
  • Objectのprototypeオブジェクトは、すべてのオブジェクトから利用できるメソッドなどを提供するベースオブジェクトとも言えます。

例えばtoStringメソッドはObjectのprototypeオブジェクトに定義があります。

// `Object.prototype`オブジェクトに`toString`メソッドの定義がある
console.log(typeof Object.prototype.toString); // => "function"

prototypeオブジェクトに組み込まれているメソッドはプロトタイプメソッドと呼ばれます。
prototypeの部分は省略しても同じ結果を得られます。

Objectのインスタンスは、このObject.prototypeオブジェクトに定義されたメソッドやプロパティを継承します。
つまり、オブジェクトリテラルやnew Objectでインスタンス化したオブジェクトは、Object.prototypeに定義されたものが利用できるということです。

本章に戻ります。

プロトタイプオブジェクト

プロトタイプメソッドインスタンスオブジェクトのメソッドをクラス内で同時に定義しても上書きされることもなければ、衝突することもありません。

なぜなら、それぞれ定義先が違うためです。

プロトタイプメソッド・・・プロトタイプオブジェクト

インスタンスオブジェクトのメソッド・・・インスタンスオブジェクト

プロトタイプオブジェクトとは、JavaScriptの関数オブジェクトのprototypeプロパティに自動的に作成される特殊なオブジェクトです。

function fn() {
}
// `prototype`プロパティにプロトタイプオブジェクトが存在する
console.log(typeof fn.prototype === "object"); // => true

class MyClass {
}
// `prototype`プロパティにプロトタイプオブジェクトが存在する
console.log(typeof MyClass.prototype === "object"); // => true

class構文のメソッド定義は、このプロトタイプオブジェクトのプロパティとして定義されます。

次のコードでは、クラスのメソッドがプロトタイプオブジェクトに定義されていることを確認できます。 また、クラスにはconstructorメソッド(コンストラクタ)が必ず定義されます。 このconstructorメソッドもプロトタイプオブジェクトに定義されており、このconstructorプロパティはクラス自身を参照します。

class MyClass {
    method() { }
}

console.log(typeof MyClass.prototype.method === "function"); // => true
// クラス#constructorはクラス自身を参照する
console.log(MyClass.prototype.constructor === MyClass); // => true

このように、プロトタイプメソッドはプロトタイプオブジェクトに定義され、インスタンスオブジェクトのメソッドとは異なるオブジェクトに定義されています。そのため、それぞれの方法でメソッドを定義しても、上書きされることはありません。

まとめ

  • プロトタイプオブジェクトとは、prototypeプロパティに自動的に作成される特殊なオブジェクトです。
  • プロトタイプメソッドとインスタンスオブジェクトに定義したメソッドの参照先は異なります。

参考

JavaScript (JS Primer) プロトタイプオブジェクト

2022年1月15日 JavaScript (JS Primer) 2種類のインスタンスメソッドの定義

クラスでは、2種類のインスタンスメソッドの定義方法があります。 class構文を使ったインスタンス間で共有されるプロトタイプメソッドの定義と、 インスタンスオブジェクトに対するメソッドの定義です。

これらの2つの方法を同時に使い、1つのクラスに同じ名前でメソッドを2つ定義した場合はどうなるでしょうか?

次のコードでは、ConflictClassクラスにプロトタイプメソッドとインスタンスに対して同じmethodという名前のメソッドを定義しています。

class ConflictClass {
    constructor() {
        // インスタンスオブジェクトに`method`を定義
        this.method = () => {
            console.log("インスタンスオブジェクトのメソッド");
        };
    }

    // クラスのプロトタイプメソッドとして`method`を定義
    method() {
        console.log("プロトタイプのメソッド");
    }
}

const conflict = new ConflictClass();
conflict.method(); // どちらの`method`が呼び出される?

結論から述べると、この場合はインスタンスオブジェクトに定義したmethodが呼び出されます。 このとき、インスタンスのmethodプロパティをdelete演算子で削除すると、今度はプロトタイプメソッドのmethodが呼び出されます。

class ConflictClass {
    constructor() {
        this.method = () => {
            console.log("インスタンスオブジェクトのメソッド");
        };
    }

    method() {
        console.log("プロトタイプメソッド");
    }
}

const conflict = new ConflictClass();
conflict.method(); // "インスタンスオブジェクトのメソッド"
// インスタンスの`method`プロパティを削除
delete conflict.method;
conflict.method(); // "プロトタイプメソッド"

呼び出し方はどちらも同じです。

インスタンス.メソッド名()

この実行結果から次のことがわかります。

プロトタイプメソッドとインスタンスオブジェクトのメソッドは上書きされずにどちらも定義されている
インスタンスオブジェクトのメソッドがプロトタイプオブジェクトのメソッドよりも優先して呼ばれている
どちらも注意深く意識しないと気づきにくいですが、この挙動はJavaScriptの重要な仕組みであるため理解することは重要です。

この挙動はプロトタイプオブジェクトと呼ばれる特殊なオブジェクトとプロトタイプチェーンと呼ばれる仕組みで成り立っています。 どちらもプロトタイプとついていることからわかるように、2つで1組のような仕組みです。

このセクションでは、プロトタイプオブジェクトとプロトタイプチェーンとはどのような仕組みなのかを見ていきます。

クラスの役割(復習)

クラスは”インスタンスを初期化する場所”という役割を持っています。
したがって、クラスは直接呼び出すことが出来ません。

  • クラスのコンストラクタは初期化する処理を書く場所であるため、returnなどで値を返すべきではありません。
  • new演算子を用いてインスタンス化します。

コンストラクタ(復習)

クラスは必ずコンストラクタを持ち、constructorという名前のメソッドとして定義します。

  • constructorメソッドに定義した処理は、クラスをインスタンス化したときに自動的に呼び出されます。
  • コンストラクタ関数の中で使われるthisは生成したインスタンスオブジェクトを指します。

プロトタイプメソッドとインスタンスオブジェクトのインスタンスメソッドの違いのまとめ (復習)

プロトタイプメソッド

  • コンストラクタ関数外でメソッドの短縮記法で定義します。

インスタンスオブジェクトのインスタンスメソッド

  • コンストラクタ関数内のthis にメソッドを定義します。

参考

JS primer 2種類のインスタンスメソッドの定義