javascript:class
差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
javascript:class [2011/07/05 17:08] – [継承] nullpon | javascript:class [2016/01/19 07:56] (現在) – [継承] nullpon | ||
---|---|---|---|
行 1: | 行 1: | ||
====== クラス ====== | ====== クラス ====== | ||
- | 厳密にはJavaScriptにクラスはない。機能の異なるオブジェクトは存在するが、それらは持っているプロパティやメソッドが異なっているだけで、オブジェクトの性質には違いはない。 | ||
- | ===== コンストラクタ ===== | + | ===== クラス構文 |
- | Construct関数を不可視プロパティとして持っているオブジェクトは、Construct関数で定義されたプロパティを持つインスタンスを生成することができる。 | + | ECMAScript 2015からクラス構文が導入された。 |
- | Construct関数を持っているオブジェクトは、いくつかのグローバルオブジェクトと、ユーザが定義した関数オブジェクトである。関数を定義すると、定義された関数オブジェクトはコンストラクタとなり、その関数自身がConstruct関数となる。 | + | <code javascript> |
+ | 'use strict'; | ||
- | ==== 標準のオブジェクト型 ==== | + | class Hoge { |
+ | // コンストラクタ | ||
+ | constructor(val) { | ||
+ | this._value | ||
+ | } | ||
+ | |||
+ | // メソッド | ||
+ | print() { | ||
+ | console.log(this._value); | ||
+ | } | ||
+ | |||
+ | // ゲッター | ||
+ | get value() { | ||
+ | return this._value; | ||
+ | } | ||
+ | |||
+ | // セッター | ||
+ | set value(val) { | ||
+ | this._value | ||
+ | } | ||
+ | } | ||
- | * Boolean | + | var hoge = new Hoge(1); |
- | * Number | + | |
- | * String | + | |
- | * Array | + | |
- | * Object | + | |
- | * Function | + | |
- | * RegExp | + | |
- | * Date | + | |
- | <code javascript> | + | hoge.print(); // => 1 と出力 |
- | var s = new String(" | + | |
- | var d = new Date(); | + | hoge.value |
+ | |||
+ | console.log(hoge.value) // => 2 と出力 | ||
</ | </ | ||
+ | これは以前のprototypeによるクラス定義のシンタックスシュガーにすぎず、Hogeは関数オブジェクトとして定義されている。 | ||
+ | |||
+ | < | ||
+ | typeof(Hoge); | ||
+ | </ | ||
+ | |||
+ | ただし関数としての呼び出しには制限がかけられており、newを付けずに呼び出すとエラーになる。 | ||
+ | |||
+ | < | ||
+ | Hoge(); | ||
+ | </ | ||
+ | |||
+ | ==== 継承 ==== | ||
+ | |||
+ | < | ||
+ | class Fuga extends Hoge { | ||
+ | // メソッド | ||
+ | print2() { | ||
+ | console.log(this._value * 2); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | var fuga = new Fuga(3); | ||
+ | |||
+ | fuga.print(); | ||
+ | fuga.print2(); | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== staticメソッド ==== | ||
+ | |||
+ | < | ||
+ | class Piyo extends Hoge{ | ||
+ | // メソッド | ||
+ | static piyo() { | ||
+ | console.log(' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | Piyo.piyo(); | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===== prototypeによるクラス定義 ===== | ||
+ | |||
+ | ここからはES5以前の話 | ||
+ | |||
+ | ==== コンストラクタ ==== | ||
- | ==== ユーザ定義のオブジェクト型 ==== | + | 関数はコンストラクタとして働く。コンストラクタとして使う関数は、慣例として大文字で名前を定義する。 |
<code javascript> | <code javascript> | ||
行 48: | 行 111: | ||
</ | </ | ||
- | コンストラクタとして使う関数は、慣例として大文字で名前を定義する。 | + | ==== constructor プロパティ ==== |
- | ===== プロトタイプ ===== | + | 生成されたインスタンスは constructor というプロパティを持っており、自分のコンストラクタにアクセスできる。 |
- | 全てのオブジェクトは constructor というプロパティを持っている。これは自分を生成したコンストラクタ関数へのリファレンスである。 | + | <code javascript> |
+ | function Greet() { | ||
+ | // ... | ||
+ | } | ||
- | constructor は prototype というオブジェクトを持っている。あるオブジェクトに対して存在しないメソッドAが呼び出された時、自分のconstructor の prototype がメソッドAを持っていれば、それが実行される。 | + | var greet = new Greet(); |
- | よってコンストラクタ関数の prototype に対してメソッドを定義すれば、そのメソッドを生成したインスタンスから呼び出す事ができる。また、prototype はインスタンス間で共有されるので無駄な関数オブジェクトが生成されることもない。(クラス定義1のようにコンストラクタ関数でメソッドを定義すると、コンストラクタを呼ぶたびに関数オブジェクトを作成するので無駄だが、prototype へのメソッド設定ならば一度で良いので無駄が無い) | + | greet.constructor; |
+ | </ | ||
- | このため、実際のプログラミングでは、メソッドは、prototype | + | ==== プロトタイプ ==== |
+ | |||
+ | コンストラクタは prototype | ||
<code javascript> | <code javascript> | ||
- | // クラス定義2 | ||
function Greet() { | function Greet() { | ||
- | | + | // ... |
+ | } | ||
+ | Greet.prototype; | ||
+ | |||
+ | var greet = new Greet(); | ||
+ | greet.constructor.prototype; | ||
+ | </ | ||
+ | |||
+ | new演算子で作成されたインスタンスは、自分のコンストラクタの prototype が持っているプロパティやメソッドに、あたかも自分のメソッドやプロパティであるかのようにアクセスできる。 | ||
+ | |||
+ | よって prototype にプロパティやメソッドを定義してインスタンスで利用することができる。ただし全てのインスタンスで共有されてしまうため、メソッドのみ prototype に定義するのが一般的である。 | ||
+ | |||
+ | <code javascript> | ||
+ | // クラス定義2 | ||
+ | function Greet(message) { | ||
+ | // プロパティ定義 | ||
+ | | ||
} | } | ||
+ | // メソッド定義 | ||
Greet.prototype.say = function() { | Greet.prototype.say = function() { | ||
return this.message | return this.message | ||
} | } | ||
- | var greet = new Greet(); | + | var greet = new Greet(" |
- | greet.say(); | + | greet.say(); |
</ | </ | ||
+ | prototypeを丸ごと上書きして置き換えることもできる。 | ||
- | prototypeを丸ごと上書きして置き換えることもできます。 | ||
<code javascript> | <code javascript> | ||
// クラス定義3 | // クラス定義3 | ||
- | function Greet() { | + | function Greet(message) { |
- | this.message = " | + | // プロパティ定義 |
+ | this.message = message; | ||
} | } | ||
行 89: | 行 175: | ||
}; | }; | ||
- | var greet = new Greet(); | + | var greet = new Greet(" |
greet.say(); | greet.say(); | ||
</ | </ | ||
- | prototypeを上書きした場合と、そうでない場合では厳密には異なるインスタンスを作成する。 | + | ==== __proto__ プロパティ ==== |
+ | |||
+ | new演算子で作成されたインスタンスは、内部的に < | ||
+ | |||
+ | <code javascript> | ||
+ | var greet = new Greet(); | ||
+ | greet.__proto__ === Greet.prototype; | ||
+ | greet.__proto__ === greet.constructor.prototype; | ||
+ | </ | ||
+ | |||
+ | これは隠しプロパティ扱いの場合もあるので、実際のプログラミングでは constructor.prototype を使うのがよい。 | ||
===== プロトタイプチェーン ===== | ===== プロトタイプチェーン ===== | ||
- | オブジェクトがプロパティを持っていなければ、コンストラクタの prototype からプロパティを探すが、その prototype も該当するプロパティを持っていなければ、さらにその prototype のコンストラクタの prototype からプロパティ探す。この仕組みをプロトタイプチェーンと呼ぶ。 | + | インスタンスは、< |
- | プロトタイプチェーンを使うと継承のような事ができるが、実際に使われる事は少ない。 | + | あるインスタンスに対してメソッドAを呼び出したとき、もし、インスタンスがメソッドAを持っておらず、プロトタイプがメソッドAを持っていれば、プロトタイプのメソッドAが呼び出される。もしプロトタイプもメソッドAを持っていなければ、プロトタイプのプロトタイプがメソッドAを持っているか探す。 |
+ | |||
+ | この仕組みをプロトタイプチェーンと呼ぶ。プロトタイプチェーンを使うと継承に似たことができる。 | ||
<code javascript> | <code javascript> | ||
行 113: | 行 211: | ||
this.message = "good night"; | this.message = "good night"; | ||
} | } | ||
- | NightGreet.prototype = new Greet(); | + | NightGreet.prototype = new Greet(); |
+ | |||
+ | function JpNightGreet() { | ||
+ | this.message = " | ||
+ | } | ||
+ | NightGreet.prototype = new NightGreet(); | ||
- | // NightGreet型のインスタンス生成 | + | // JpNightGreet型のインスタンス生成 |
- | var nightGreet | + | var jpNightGreet |
- | // Greet型のメソッドsayが呼び出される | + | // Greet型の(プロトタイプのプロトタイプ)メソッドsayが呼び出される |
- | nightGreet.say(); | + | jpNightGreet.say(); |
</ | </ | ||
+ | プロトタイプチェーンを最後までさかのぼると、最終的にはObjectになる。よってObjectのメソッドは全てのインスタンスから呼び出すことができる。(といってもvalueOfとtoString、toSourceぐらいしか無い) |
javascript/class.1309885685.txt.gz · 最終更新: 2011/07/05 17:08 by nullpon