Javascriptの中の構造関数
3651 ワード
工場モード
コンストラクタモードは、オブジェクトを明示的に作成していません. は直接に属性と方法をthisオブジェクトに与えた. には 前の例の最後に、
コンストラクタを関数として使う
コンストラクタと他の関数との唯一の違いは,それらを呼び出す方法が異なることにある.しかし、コンストラクタは結局関数であり、コンストラクタを定義する特殊な文法は存在しない.任意の関数は、
コンストラクタを使用する主要な問題は、各方法が各インスタンスで再作成されます.前の例では、
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.job = job;
o.sayName = function () {
alert(this.name);
};
return o;
}
var person1 = createPerson("Mike", 29, "Dev");
var person2 = createPerson("Greg", 27, "Doctor");
工場モードでは、似たようなオブジェクトを複数作成する問題を解決しましたが、対象認識の問題は解決されませんでした.コンストラクタモード
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
alert(this.name);
};
}
var person1 = new Person("Mike", 29, "Dev");
var person2 = new Person("Greg", 27, "Doctor");
コンストラクタモードは工場モードと比較します.return
文がありません.person1
およびperson2
はそれぞれPerson
の異なる例を保存している.これらの2つのオブジェクトは、constructor
(構造関数)属性を持っています.この属性はPerson
を指しています.alert(person1.constructor === Person); //true
alert(person2.constructor === Person); //true
私たちが作成したオブジェクトはObject
の例であり、Person
の例でもあります.alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true
カスタムコンストラクタを作成すると、将来はそのインスタンスを特定のタイプとして識別することができるということです.これは工場モデルよりも構造関数モードの方が優れているところです.この例では、instanceof
が同時にperson1
の例であるのは、すべてのオブジェクトがObject
から継承されているからである.コンストラクタを関数として使う
コンストラクタと他の関数との唯一の違いは,それらを呼び出す方法が異なることにある.しかし、コンストラクタは結局関数であり、コンストラクタを定義する特殊な文法は存在しない.任意の関数は、
Object
オペレータを介して呼び出されれば、構築関数として機能することができる.どの関数も、new
オペレータを介して呼び出さなければ、普通の関数と同じではない.//
var person = new Person("Mike", 29, "Dev");
person.sayName(); // "Mike"
//
Person("Greg", 27, "Doctor"); // window
window.sayName(); // "Greg"
//
var o = new Object();
Person.call(0, "Kristen", 25, "Nurse");
o.sayName(); // "Kristen"
構造関数の問題コンストラクタを使用する主要な問題は、各方法が各インスタンスで再作成されます.前の例では、
new
およびperson1
はいずれもperson2
という方法があるが、その2つの方法は同じsayName()
の例ではない.ECMAScriptの関数はオブジェクトですので、関数を定義するごとにオブジェクトを実例化しました.論理的には、この時の構造関数もこのように定義されています.function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = new Function("alert(this.name)");
}
この観点からコンストラクタを見ると、各Function
例は、異なるPerson
例の本質を含むことが分かりやすい.このように構成関数を作成すると、異なる作用ドメインチェーンおよび識別子解析が生じるが、Function
の新しいインスタンスを作成するメカニズムは依然として同じである.したがって、異なる例における同名関数は、等ではない.以下のコードはこの点を証明できます.alert(person1.sayName === person2.sayName); //false
しかし、完全に同じタスクを2つ作成するFunction
の例は、必要ではない.さらに、Function
オブジェクトがあります.コードを実行する前に関数を特定のオブジェクトに結びつける必要はありません.従って、この問題は以下のように関数定義を構造関数の外部に移すことによって解決できる.function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName() {
alert(this.name);
}
この例では、this
関数の定義を構造関数の外部に転送します.構造関数の内部では、sayName()
属性を大域のsayName
関数に等しく設定します.このように、sayName
は関数を指すポインタを含むので、sayName
およびperson1
オブジェクトは、グローバルスコープで定義された同じperson2
関数を共有する.このようにして確かに二つの関数が同じことをする問題を解決しましたが、新しい問題がまた来ました.グローバルスコープで定義された関数は実際にはある対象にしか呼び出されません.さらに納得できないのは、対象がいろいろな方法を定義する必要があるなら、多くの大域関数を定義しなければならないので、私たちのカスタム引用のタイプはパッケージ性が全くないということです.幸いにも、これらの問題はプロトタイプによって解決できます.