(2001.10.11) 新規作成。
ECMAScript / JavaScriptは,プロトタイプベースな (prototype-based) オブジェクト指向言語。Java、Rubyなどメジャーなプログラミング言語は、プロトタイプベースではなく、クラスベース (class-based)。
プロトタイプベースのプログラミング言語には、例えば, 次がある.
クラスベースのオブジェクト指向言語では、まずオブジェクト (インスタンス) の雛型となるクラスを定義する。クラスにプロパティ (メンバ変数)、メソッドなどを定義する。オブジェクトはクラスから生成する。クラスが同じであれば, それぞれのオブジェクトは同じメソッドを持つ。
JavaScriptでは,クラスというものがなく、それぞれのオブジェクトにメソッド、プロパティを定義する。また、JavaScriptのオブジェクトはただのハッシュで、(プロパティ名: プロパティ値) の集まり。プロパティ値が関数であれば, それがメソッドになる。
JavaScriptでは、オブジェクトは 関数をコンストラクタと見立てる. この関数の名前 ( 次の例の [[Prototype]] 内部プロパティと、 コンストラクタの コンストラクタが何を返すかで, 生成されるオブジェクトが変わるのが微妙。 オブジェクトは、# 概要
# オブジェクトの生成
new
演算子で生成する。
name
プロパティ) がクラス名になる.
new
関数オブジェクト ( 引数 )
Hoge()
はただの関数。これを引数として new
演算子を実行すると, 次のような動作を行う;
new
演算子の対象F をコンストラクタとする.
TypeError
を投げる.
"Object"
とする
prototype
プロパティを持ち, それが Object
である場合, それ.
Object
の prototype
プロパティ
this
は 1. で生成したオブジェクトを指す。引数は new
演算子に与えたもの.
prototype
プロパティとは別物。
prototype
プロパティにメソッドを設定することで、新しく生成されたオブジェクトのメソッドになる。
null
はプリミティブ値なので、コンストラクタがnull
を返したときは新たに生成されたオブジェクトがnew
演算子の値になる。下手にオブジェクトを返してしまうと、それになってしまう。
constructor
プロパティを持ち、このプロパティはオブジェクトを生成した関数を指す。
JavaScript はクラスベースではないので、オブジェクトのクラスを差し替えることができる。
JSON文字列をオブジェクト化したもののクラスを差し替えてみよう。次の例は, Object.setPrototypeOf()
を使い, Foo
クラスオブジェクトに変更している。
JavaScriptのメソッドはただの関数で、オブジェクトのプロパティ値として参照されるもの。呼び出しのときのレシーバが Object.setPrototypeOf()
は ES2015 (ES6) で導入された。[[Prototype]] 内部プロパティを変更する。
# メソッド定義
this
に格納される.
メソッドはただの関数なので, レシーバなしでも呼び出せる。クラス間で使いまわしもできる。
レシーバなしに呼び出したとき, strictモードでは this
は undefined になる。non-strictモードでは window になる.
this
のスコープ関数がクラスに従属しないのが JavaScript の特徴だが、this
が状況によって想定しないオブジェクトを指すのは、混乱のもとになることが多い。
this
は、他の変数と異なり、dynamic scope を持つ。字面上の外側でなく, 呼出し元の値を引き継ぐ。
次の例の data.map()
に与えている関数内の this
は, lexical に外側の this
にはならず, map()
がレシーバなしで呼び出すために undefined
になる。
this
を強制的に固定するために, bind
関数がある。呼び出しのつどレシーバを差し替えるのは call
関数.
次の例は, メソッド (実体はたたの関数) の this
を固定するために, コンストラクタ内で bind()
している。コンストラクタ内では, this
は必ずクラスのオブジェクトになるので。
ES2015 (ES6) で導入された「アロー関数」(Arrow function) は、基本的には無名関数の短い書き方だが、this
を lexically に束縛 (bind) する点がことなる。
アロー関数は、定義した時点の this
を bind するので、上の例は呼び出し方に関わらず、this
はクラスのオブジェクトを指すようになる。