Javascriptのオブジェクト向けを整理する(一)——プロトタイプ継承
6383 ワード
他のプログラミング言語とは異なり、javascriptのオブジェクト向けは抽象的なクラスに依存するのではなく、
JAvascriptは、最も基礎的なオブジェクトタイプ
実際には,オブジェクト指向性の方が構造関数を用いてオブジェクトインスタンスを生成するべきである.
他のプログラミング言語では、
上の図から分かるように、コンストラクション関数Aを用いて生成されるインスタンスオブジェクトobjのデータ型はAであり、また、objには
以上から分かるように、オブジェクトインスタンスを生成するには、
引き続き上記の例を用いて、今回は構造関数Aを印刷して、どのように成長しているかを見てみましょう.
実際には、コンストラクション関数は通常の関数と変わらないが、用途(オブジェクトインスタンスを生成するために使用される)のため、コンストラクション関数の名前が付けられているだけだ.上図から、オブジェクト向けに関係のないプロパティ(arguments/caller/length/name)と、その関数役割ドメイン(
特に「コンストラクション関数の
コンストラクション関数の
まず、コンストラクション関数audiが印刷した結果を見てみましょう.
audiからprototype.statusはこの時のaudiを見ることができる.prototypeは確かに
audiQ 3というインスタンスオブジェクトのデータ型は
オブジェクトインスタンスの
コンストラクション関数は、主にオブジェクトの作成時にオブジェクトを初期化するために使用されます.すなわち、オブジェクトメンバー変数に初期値を割り当てるために使用されます.では、javascriptのコンストラクション関数は、どのようにしてこのような機能を実現しますか.以下のDEMOを例として説明する.
まず構造関数carを見てみると、
Object.create(proto, [ propertiesObject ])
protoは、新しく作成されたオブジェクトのプロトタイプとしてオブジェクトです.
propertiesObjectはオプションです.このパラメータ・オブジェクトは、新しく作成されたオブジェクトの属性名である属性と値のセットです.値は属性記述子です(これらの属性記述子の構造はObject.defineProperties()の2番目のパラメータと同じです).注意:このパラメータオブジェクトはundefinedではなく、オブジェクト自体が持つ列挙可能な属性のみが有効です.つまり、オブジェクトのプロトタイプチェーン上の属性は無効です.
どうすれば、
を介して特定のオブジェクトインスタンスを接続し、プロトタイプチェーンの下流にあるオブジェクトインスタンスは上流にあるオブジェクトインスタンスの属性/方法を読み取り/使用することができる.以下では,javascriptのオブジェクト向けの本質を一歩一歩整理しようとする.万物の源:javascriptの原生タイプ――Object
JAvascriptは、最も基礎的なオブジェクトタイプ
Object
を定義し、このオブジェクトタイプのために多くのメンバーメソッドを定義します.他の多くのオリジナルオブジェクトタイプは、実際にはObject
、例えばFunction
、Date
などから継承される.Object
オブジェクトタイプのオブジェクトインスタンスを生成するのも難しいことではありません.var obj = {a: 2333};
// Object()
var obj = new Object();
実際には,オブジェクト指向性の方が構造関数を用いてオブジェクトインスタンスを生成するべきである.
オブジェクトインスタンスを生成する演算子newと構造関数constructor
newという演算子を使用してオブジェクトインスタンスを生成する方法
他のプログラミング言語では、
new
もオブジェクトインスタンスを生成するために使用されることが多い.一般的には、new ClassName[([arguments])]
であり、生成されたオブジェクトインスタンスも「ClassNameオブジェクト」という呼称を冠している.Javascriptは大きく異なり、原生にはクラスという概念がないため、
はnew constructor[([arguments])]
に代わり、呼称も「constructorオブジェクト」や「constructorタイプのオブジェクト」に変更され、構造関数名は直接データ型に等しい.function A() {} // ( , ) A。
var obj = new A(); // A obj
console.dir(obj); // obj
上の図から分かるように、コンストラクション関数Aを用いて生成されるインスタンスオブジェクトobjのデータ型はAであり、また、objには
__proto__
の属性が1つしかないことに留意すると、これは何であるか.焦らないで、後で話します.コンストラクション関数constructorの詳細
以上から分かるように、オブジェクトインスタンスを生成するには、
constructor
またはvar arr = [];
のような形式であってもjavascriptは、var obj = {}
、Function()
のような予め設定された構造関数を内部的に呼び出す(予め設定された構造関数/データ型であるため、明示的に指定する必要はない).引き続き上記の例を用いて、今回は構造関数Aを印刷して、どのように成長しているかを見てみましょう.
function A() {}
var obj = new A();
console.dir(A);
実際には、コンストラクション関数は通常の関数と変わらないが、用途(オブジェクトインスタンスを生成するために使用される)のため、コンストラクション関数の名前が付けられているだけだ.上図から、オブジェクト向けに関係のないプロパティ(arguments/caller/length/name)と、その関数役割ドメイン(
Object()
)を省略します.残りはオブジェクト向けに密接に関係する2つのプロパティです.
とprototype
です.この__proto__
は見覚えがあり、オブジェクトインスタンスobjにも登場しますが、ここではスキップしておきます.この__proto__
属性についてお話しします.コンストラクション関数のprototypeプロパティ
特に「コンストラクション関数の
prototype
属性」と明記されているのは、一般的な関数にとってprototype
属性は意味がないからである.prototype
プロパティは、コンストラクション関数を使用して生成されたオブジェクトインスタンスがどのオブジェクトインスタンスを継承するかを指定します.上記のfunction A()のprototype
属性がデフォルトのprototype
タイプのオブジェクトインスタンスを指すように(javascriptでは変数はオブジェクトインスタンスの参照にすぎないので、ここでは「指向」が比較的正確である)、function A()をコンストラクション関数としてインスタンス化したobjは、実際にはデフォルトのObjectタイプのオブジェクトインスタンスを継承しているが、obj自体にはカスタム属性/方法はないが、ただし、objによって継承されたすべての属性/メソッドを呼び出すことができます.オブジェクト継承の一方向チェーンおぶじぇくとけいぞくの一方向チェーン:プロトタイプチェーンプロトタイプれんさ
コンストラクション関数の
Object
プロパティが継承されたオブジェクトインスタンスを指定できる以上、このprototype
プロパティを変更して他のオブジェクトインスタンスを指すようにすれば、次のコードを参照してください.var car = { // Object
status: 'stop'
}
function audi() {} // audi
audi.prototype = car; // audi prototype , car
console.dir(audi);
var audiQ3 = new audi(); // audi audi
console.dir(audiQ3);
まず、コンストラクション関数audiが印刷した結果を見てみましょう.
audiからprototype.statusはこの時のaudiを見ることができる.prototypeは確かに
prototype
というオブジェクトのインスタンスを指しています.次に、修正したコンストラクション関数audiを用いて生成するオブジェクトインスタンスaudiQ 3を見る.audiQ 3というインスタンスオブジェクトのデータ型は
{status: 'stop'}
(コンストラクション関数と同名)であることがわかります.また、audiQ 3の下にはaudi
という唯一のメンバー属性しかありません.__proto__
を引き続き見てみると、__proto__
が入っています.そう、status: "stop"
プロパティは、__proto__
というオブジェクトインスタンスへの参照です.プロトタイプチェーンの接点:{status:'stop'}
オブジェクトインスタンスの
__proto__
プロパティによって、継承されたオブジェクトインスタンスが継承されたオブジェクトインスタンスにリンクされ、ループがループされ、オブジェクトインスタンス、継承されたオブジェクトインスタンスへの参照からなるチェーン:プロトタイプチェーンが形成される.__proto__
は、コンストラクション関数の__proto__
属性によって決定される(prototype
がprototype
に直接付与されるとも言える)ため、__proto__
属性を修正することによって、このprototype
を操作することができる.コンストラクション関数について
コンストラクション関数は、主にオブジェクトの作成時にオブジェクトを初期化するために使用されます.すなわち、オブジェクトメンバー変数に初期値を割り当てるために使用されます.では、javascriptのコンストラクション関数は、どのようにしてこのような機能を実現しますか.以下のDEMOを例として説明する.
function car() { // car
this.status = 'stop'; // car status , 'stop'
this.start = function() { // start
this.status = 'running';
}
}
var audiQ3 = new car(); // car , audiQ3
console.dir(audiQ3);
audiQ3.start(); // audiQ3 start
console.dir(audiQ3);
まず構造関数carを見てみると、
が見えます.このthis.status = 'stop';
はcarというfunctionを指していますか.いいえ、このthis
は実際には現在の関数の実行時のコンテキスト環境を指し、関数を構築する際に使用されるのは新しく生成されたオブジェクトインスタンスを指します(本DEMOではaudiQ 3を指します).したがって,this
を利用すれば,コンストラクション関数において,将来このコンストラクション関数を利用して生成されるオブジェクトインスタンスにメンバ属性とメンバメソッドを追加することができる.JAvascriptオリジナルサポートのプロトタイプ継承方法:this
Object.create
は、原生のプロトタイプ継承方式を定義している:ECMAScript 5
、私たちはこのような方法でプロトタイプ継承をより簡便に実現することができる.構文
Object.create(proto, [ propertiesObject ])
パラメータ
protoは、新しく作成されたオブジェクトのプロトタイプとしてオブジェクトです.
propertiesObjectはオプションです.このパラメータ・オブジェクトは、新しく作成されたオブジェクトの属性名である属性と値のセットです.値は属性記述子です(これらの属性記述子の構造はObject.defineProperties()の2番目のパラメータと同じです).注意:このパラメータオブジェクトはundefinedではなく、オブジェクト自体が持つ列挙可能な属性のみが有効です.つまり、オブジェクトのプロトタイプチェーン上の属性は無効です.
例
var car = {
status: 'stop',
start: function() {
this.status = 'running'
}
}
var audiQ3 = Object.create(car);
console.dir(audiQ3);
どうすれば、
Object.create
という方法で簡単にプロトタイプ継承が実現できるのでしょうか.実際には、Object.create
がパッケージを作ってくれました.function (proto) {
var constructor = function(){}
constructor.prototype = proto;
return new constructor();
}
ブラウザ互換性の修復
ECMAScript 5
がIE上でECMAScript 5
まで完全にサポートされていることを考慮して、低バージョンのIEブラウザを互換化する必要があります.実際には簡単です.上のコードを少し修正すればいいです.if(typeof Object.create !== 'function') {
Object.create = function(proto) {
var constructor = function(){}
constructor.prototype = proto;
return new constructor();
}
}