javascript:class
差分
このページの2つのバージョン間の差分を表示します。
次のリビジョン | 前のリビジョン | ||
javascript:class [2010/02/08 05:43] – 外部編集 127.0.0.1 | javascript:class [2016/01/19 07:56] (現在) – [継承] nullpon | ||
---|---|---|---|
行 1: | 行 1: | ||
====== クラス ====== | ====== クラス ====== | ||
- | JavaScriptにはクラスはないが、関数オブジェクトをコンストラクタとして呼び出すことができる。 | ||
- | ===== Functionオブジェクト ===== | + | ===== クラス構文 |
- | 関数を定義すると、新しい Function オブジェクトが作成されます。 | + | |
+ | ECMAScript 2015からクラス構文が導入された。 | ||
<code javascript> | <code javascript> | ||
- | function ClassA(){ | + | 'use strict'; |
+ | |||
+ | class Hoge { | ||
+ | // コンストラクタ | ||
+ | constructor(val) { | ||
+ | this._value = val | ||
+ | } | ||
+ | |||
+ | // メソッド | ||
+ | print() { | ||
+ | console.log(this._value); | ||
+ | } | ||
+ | |||
+ | // ゲッター | ||
+ | get value() { | ||
+ | return this._value; | ||
+ | } | ||
+ | |||
+ | // セッター | ||
+ | set value(val) { | ||
+ | this._value = val; | ||
+ | } | ||
} | } | ||
- | window.alert(ClassA instanceof Function); // true | + | |
+ | var hoge = new Hoge(1); | ||
+ | |||
+ | hoge.print(); // => 1 と出力 | ||
+ | |||
+ | hoge.value = 2; | ||
+ | |||
+ | console.log(hoge.value) | ||
</ | </ | ||
- | ===== クラスを定義とインスタンス作成 ===== | + | これは以前のprototypeによるクラス定義のシンタックスシュガーにすぎず、Hogeは関数オブジェクトとして定義されている。 |
- | Functionオブジェクトに演算子 new を使うと新しいインスタンスを作成できます。Function | + | |
- | < | + | < |
- | function MyClass(){ | + | typeof(Hoge); |
- | } | + | |
- | var my = new MyClass(); | + | |
- | window.alert(my instanceof MyClass); | + | |
- | window.alert(my.constructor | + | |
</ | </ | ||
- | インスタンス my の constructor プロパティは 関数オブジェクト MyClass となり、my は MyClass のインスタンスとみなされます。 | ||
- | ===== メソッド定義 ===== | + | ただし関数としての呼び出しには制限がかけられており、newを付けずに呼び出すとエラーになる。 |
- | コンストラクタは prototype プロパティを持っており、 | + | |
- | < | + | < |
- | function MyClass(){ | + | Hoge(); // => TypeError: Class constructors cannot be invoked without ' |
+ | </ | ||
+ | |||
+ | ==== 継承 ==== | ||
+ | |||
+ | < | ||
+ | class Fuga extends Hoge { | ||
+ | // メソッド | ||
+ | print2() { | ||
+ | console.log(this._value * 2); | ||
+ | } | ||
} | } | ||
- | MyClass.prototype.execute = function () { | ||
- | window.alert(" | ||
- | }; | ||
- | var my = new MyClass(); | ||
- | my.execute(); | ||
- | var my2 = new MyClass(); | + | var fuga = new Fuga(3); |
- | my2.execute(); // hogeと表示 | + | |
+ | fuga.print(); // => 3 と出力 | ||
+ | fuga.print2(); | ||
</ | </ | ||
- | インスタンスに直接メソッドを付加することもできます | + | |
- | < | + | ==== staticメソッド |
- | // インスタンス自身にメソッドを定義 | + | |
- | my.execute2 = function | + | < |
- | window.alert(" | + | class Piyo extends Hoge{ |
- | }; | + | |
- | my.execute2(); | + | |
- | my2.execute2(); // my2はメソッドexecute2を持たないのでエラー | + | |
+ | } | ||
+ | } | ||
+ | |||
+ | Piyo.piyo(); // => ピヨピヨ と出力 | ||
</ | </ | ||
- | ==== プロトタイプチェイン | + | |
- | メソッドを呼び出すと、まずインスタンス自身が呼び出されたメソッドを持っていないかチェックし、持っていればそれを実行します。 | + | ===== prototypeによるクラス定義 ===== |
+ | |||
+ | ここからはES5以前の話 | ||
+ | |||
+ | ==== コンストラクタ ==== | ||
+ | |||
+ | 関数はコンストラクタとして働く。コンストラクタとして使う関数は、慣例として大文字で名前を定義する。 | ||
<code javascript> | <code javascript> | ||
- | function | + | // クラス定義1 |
+ | // コンストラクタ関数 | ||
+ | function | ||
+ | // プロパティの定義 | ||
+ | this.message = " | ||
+ | |||
+ | // メソッドの定義 | ||
+ | this.say = function() { | ||
+ | return this.message; | ||
+ | }; | ||
} | } | ||
- | var hoge = new Hoge(); | ||
- | hoge.execute = function() { alert(" | ||
- | hoge.execute(); // " | + | // インスタンスの生成 |
+ | var greet = new Greet(); | ||
+ | |||
+ | // メソッドの呼び出し | ||
+ | greet.say(); | ||
</ | </ | ||
- | インスタンス自身がメソッドをもっていない場合は、コンストラクタのprototypeからメソッドを探して呼び出します。 | + | |
+ | ==== constructor プロパティ ==== | ||
+ | |||
+ | 生成されたインスタンスは constructor というプロパティを持っており、自分のコンストラクタにアクセスできる。 | ||
<code javascript> | <code javascript> | ||
- | function | + | function |
+ | // ... | ||
} | } | ||
- | Fuga.prototype = hoge; | ||
- | var fuga = new Fuga(); | + | var greet = new Greet(); |
- | fuga.execute(); // プロトタイプ(hoge)のexecuteメソッドが呼ばれ、" | + | |
+ | greet.constructor; | ||
</ | </ | ||
- | コンストラクタのprototypeもメソッドを持っていない場合は、prototypeオブジェクトのコンストラクタのprototypeを探して呼び出します。 | + | ==== プロトタイプ ==== |
+ | |||
+ | コンストラクタは prototype | ||
<code javascript> | <code javascript> | ||
- | function | + | function |
+ | // ... | ||
} | } | ||
- | Piyo.prototype | + | Greet.prototype; |
- | var piyo = new Piyo(); | + | var greet = new Greet(); |
- | piyo.execute(); // プロトタイプ(Fugaのインスタンス)のプロトタイプ(hoge)の execute メソッドが呼ばれ、" | + | greet.constructor.prototype; |
</ | </ | ||
- | このようにプロトタイプをさかのぼってメソッドを探す仕組みをプロトタイプチェインと呼びます。 | + | new演算子で作成されたインスタンスは、自分のコンストラクタの |
+ | よって prototype にプロパティやメソッドを定義してインスタンスで利用することができる。ただし全てのインスタンスで共有されてしまうため、メソッドのみ prototype に定義するのが一般的である。 | ||
- | ===== プロパティの定義 ===== | ||
- | 代入式を実行した時点でプロパティが生成されるのでプロパティを宣言をする必要はありません。 | ||
<code javascript> | <code javascript> | ||
- | function | + | // クラス定義2 |
- | | + | function |
+ | // プロパティ定義 | ||
+ | this.message = message; | ||
} | } | ||
- | MyClass.prototype.printHoge = function () { | + | |
- | | + | // メソッド定義 |
- | } | + | Greet.prototype.say = function() { |
- | MyClass.prototype.printFuga | + | |
- | | + | } |
- | } | + | |
- | MyClass.prototype.setMohe = function (mohe) { | + | var greet = new Greet(" |
- | this.mohe = mohe; | + | |
- | } | + | greet.say(); // => "hello" |
- | var my = new MyClass(); | + | |
- | my.printHoge(); | + | |
- | my.fuga | + | |
- | my.printFuga(); | + | |
- | my.setMohe(" | + | |
- | print(my.mohe); | + | |
</ | </ | ||
- | メソッドやプロパティは全て外部から自由にアクセス可能。内部表現の隠蔽は難しい(できなくはない…) | ||
- | ===== クラス定義 ===== | + | prototypeを丸ごと上書きして置き換えることもできる。 |
- | 最近では | + | |
<code javascript> | <code javascript> | ||
- | function | + | // クラス定義3 |
- | this.initialize(arg); | + | function |
+ | // プロパティ定義 | ||
+ | this.message = message; | ||
} | } | ||
- | MyClass.prototype = { | + | |
- | | + | Greet.prototype = { |
- | | + | |
- | } | + | |
- | printHoge: function() { | + | } |
- | | + | |
- | }, | + | |
- | printFuga: function () { | + | |
- | print(this.fuga); | + | |
- | }, | + | |
- | setMohe: function (mohe) { | + | |
- | this.mohe = mohe; | + | |
- | } | + | |
}; | }; | ||
- | var my = new MyClass("ほげ"); | + | |
- | my.printHoge(); | + | var greet = new Greet("world"); |
- | my.fuga = " | + | |
- | my.printFuga(); | + | greet.say(); |
- | my.setMohe(" | + | |
- | window.alert(my.mohe); | + | |
</ | </ | ||
- | ===== 無名関数からクラスを生成 ===== | + | ==== __proto__ プロパティ |
- | 無名関数もコンストラクタになる。 | + | |
+ | new演算子で作成されたインスタンスは、内部的に < | ||
<code javascript> | <code javascript> | ||
- | var MyClass | + | var greet = new Greet(); |
- | this.initialize(arg); | + | greet.__proto__ === Greet.prototype; |
+ | greet.__proto__ === greet.constructor.prototype; | ||
+ | </ | ||
+ | |||
+ | これは隠しプロパティ扱いの場合もあるので、実際のプログラミングでは constructor.prototype を使うのがよい。 | ||
+ | |||
+ | ===== プロトタイプチェーン ===== | ||
+ | |||
+ | インスタンスは、< | ||
+ | |||
+ | あるインスタンスに対してメソッドAを呼び出したとき、もし、インスタンスがメソッドAを持っておらず、プロトタイプがメソッドAを持っていれば、プロトタイプのメソッドAが呼び出される。もしプロトタイプもメソッドAを持っていなければ、プロトタイプのプロトタイプがメソッドAを持っているか探す。 | ||
+ | |||
+ | この仕組みをプロトタイプチェーンと呼ぶ。プロトタイプチェーンを使うと継承に似たことができる。 | ||
+ | |||
+ | <code javascript> | ||
+ | function | ||
+ | this.message = " | ||
} | } | ||
- | MyClass.prototype = { | + | Greet.prototype.say = function() { |
- | initialize: | + | |
- | this.hoge = arg; | + | |
- | | + | |
- | inspect: function() { | + | |
- | print(this.prototype); | + | |
- | print(this.constructor); | + | |
- | for (var i in this) { | + | |
- | print (i + " | + | |
- | } | + | |
- | } | + | |
} | } | ||
- | var my = new MyClass(1000); | + | function NightGreet() { |
- | my.fuga = "fugafuga"; | + | this.message = "good night"; |
- | my.inspect(); | + | } |
+ | NightGreet.prototype | ||
+ | |||
+ | function JpNightGreet() { | ||
+ | this.message | ||
+ | } | ||
+ | NightGreet.prototype = new NightGreet(); | ||
+ | |||
+ | |||
+ | // JpNightGreet型のインスタンス生成 | ||
+ | var jpNightGreet = new JpNightGreet(); | ||
+ | |||
+ | // Greet型の(プロトタイプのプロトタイプ)メソッドsayが呼び出される | ||
+ | jpNightGreet.say(); | ||
</ | </ | ||
+ | プロトタイプチェーンを最後までさかのぼると、最終的にはObjectになる。よってObjectのメソッドは全てのインスタンスから呼び出すことができる。(といってもvalueOfとtoString、toSourceぐらいしか無い) |
javascript/class.1265607815.txt.gz · 最終更新: 2011/07/05 17:01 (外部編集)