文書の過去の版を表示しています。
クラス
厳密にはJavaScriptにクラスはない。機能の異なるオブジェクトは存在するが、それらは持っているプロパティやメソッドが異なっているだけで、オブジェクトの性質には違いはない。
コンストラクタ
Construct関数を不可視プロパティとして持っているオブジェクトは、new 演算子によって新しいオブジェクト(インスタンス)を生成することができる。
いくつかのグローバルオブジェクトと、ユーザが定義した関数オブジェクトがConstruct関数を持っている。
全てのユーザ定義関数は、自分自身をConstruct関数として持っているので、ユーザ定義関数は全て自動的にコンストラクタとなる。
標準のオブジェクト型
- Boolean
- Number
- String
- Array
- Object
- Function
- RegExp
- Date
var s = new String("a"); var d = new Date();
ユーザ定義のオブジェクト型
コンストラクタとして使う関数は、慣例として大文字で名前を定義する。
// クラス定義1 // コンストラクタ関数 function Greet() { // プロパティの定義 this.message = "hello"; // メソッドの定義 this.say = function() { return this.message; }; } // インスタンスの生成 var greet = new Greet(); // メソッドの呼び出し greet.say();
constructor プロパティ
生成されたインスタンスは constructor というプロパティを持っており、自分のコンストラクタにアクセスできる。
function Greet() { // ... } var greet = new Greet(); greet.constructor; // => Greet
プロトタイプ
コンストラクタは prototype というプロパティを持っている。
function Greet() { // ... } Greet.prototype; // => Greet { } var greet = new Greet(); greet.constructor.prototype; // => Greet { }
new演算子で作成されたインスタンスは、自分のコンストラクタの prototype が持っているプロパティやメソッドに、あたかも自分のメソッドやプロパティであるかのようにアクセスできる。
よって prototype にプロパティやメソッドを定義してインスタンスで利用することができる。ただし全てのインスタンスで共有されてしまうため、メソッドのみ prototype に定義するのが一般的である。
// クラス定義2 function Greet(message) { // プロパティ定義 this.message = message; } // メソッド定義 Greet.prototype.say = function() { return this.message } var greet = new Greet("hello"); greet.say(); // => "hello"
prototypeを丸ごと上書きして置き換えることもできる。
// クラス定義3 function Greet(message) { // プロパティ定義 this.message = message; } Greet.prototype = { say: function() { return this.message } }; var greet = new Greet("world"); greet.say();
__proto__
new演算子で作成されたインスタンスは、内部的に <html>proto</html> というプロパティを持っている。これはコンストラクタ関数の prototype と全くオブジェクトを参照している。
var greet = new Greet(); greet.__proto__ === Greet.prototype; // => true greet.__proto__ === greet.constructor.prototype; // => true
これは隠しプロパティ扱いの場合もあるので、実際のプログラミングでは constructor.prototype を使うのがよい。
プロトタイプチェーン
インスタンスは、<html>proto</html>(以下プロトタイプと呼ぶ)が持っているメソッドやプロパティを、自分のメソッドやプロパティであるかのように呼び出すことができる。
あるインスタンスに対してメソッドAを呼び出したとき、もし、インスタンスがメソッドAを持っておらず、プロトタイプがメソッドAを持っていれば、プロトタイプのメソッドAが呼び出される。もしプロトタイプもメソッドAを持っていなければ、プロトタイプのプロトタイプがメソッドAを持っているか探す。
この仕組みをプロトタイプチェーンと呼ぶ。プロトタイプチェーンを使うと継承に似たことができる。
function Greet() { this.message = "hello"; } Greet.prototype.say = function() { return this.message } function NightGreet() { this.message = "good night"; } NightGreet.prototype = new Greet(); // Greetを継承 function JpNightGreet() { this.message = "おやすみなさい"; } NightGreet.prototype = new NightGreet(); // NightGreetを継承 // JpNightGreet型のインスタンス生成 var jpNightGreet = new JpNightGreet(); // Greet型の(プロトタイプのプロトタイプ)メソッドsayが呼び出される jpNightGreet.say();
プロトタイプチェーンを最後までさかのぼると、最終的にはObjectになる。よってObjectのメソッドは全てのインスタンスから呼び出すことができる。(といってもvalueOfとtoString、toSourceぐらいしか無い)