js中面向?qū)ο缶幊淌腔?構(gòu)造函數(shù)(consstructor)和原型鏈(prototype)?的联四。
構(gòu)造函數(shù)作為對象的模板危队。所謂構(gòu)造函數(shù)讨彼,就是提供一個生成對象的模板,并描述對象的基本結(jié)構(gòu)的函數(shù)兄淫。一個構(gòu)造函數(shù),可以生成多個對象蔓姚,每個對象都有相同的結(jié)構(gòu)捕虽。
為了與普通函數(shù)區(qū)別,構(gòu)造函數(shù)名字的第一個字母通常大寫坡脐。函數(shù)體內(nèi)使用this關(guān)鍵字泄私,代表所要生成的對象實(shí)例。生成對象時备闲,必須使用new命令來調(diào)用構(gòu)造函數(shù)晌端。
object?instanceof?constructor
instanceof?運(yùn)算符用來檢測?constructor.prototype?是否存在于參數(shù)?object?的原型鏈上。
new 命令
new命令的作用就是執(zhí)行構(gòu)造函數(shù)并返回一個對象實(shí)例恬砂。執(zhí)行時 順序?yàn)椋?/p>
1咧纠、創(chuàng)建新的空對象,作為將要返回的對象實(shí)例泻骤。
2惧盹、將空對象的原型指向構(gòu)造函數(shù)的prototype屬性
3、將空對象賦值給構(gòu)造函數(shù)內(nèi)部的this關(guān)鍵字
4瞪讼、開始執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼钧椰。
基本用法
new命令的作用,就是調(diào)用一個構(gòu)造函數(shù)符欠,并且返回一個對象實(shí)例嫡霞。
function Keith() {
? ? ? this.height = 180;
?}
var boy = new Keith();
console.log(boy.height); //180
上面代碼中通過new命令,讓構(gòu)造函數(shù)Keith生成一個對象實(shí)例希柿,并賦值給全局變量boy诊沪。這個新生成的對象實(shí)例养筒,從構(gòu)造函數(shù)Keith中繼承了height屬性。也就說明了這個對象實(shí)例是沒有height屬性的端姚。在new命令執(zhí)行時晕粪,就代表了新生成的對象實(shí)例boy。this.height表示對象實(shí)例有一個height屬性渐裸,它的值是180巫湘。
使用new命令時,根據(jù)需要昏鹃,構(gòu)造函數(shù)也可以接受參數(shù)尚氛。
function Person(name, height) {
? ? ? ?this.name = name;
? ? ? ? this.height = height;
}
var boy = new Person('Keith', 180);
console.log(boy.name); //'Keith'
console.log(boy.height); //180
var girl = new Person('Samsara', 160);
console.log(girl.name); //'Samsara'
console.log(girl.height); //160
用以上的一個例子,來對構(gòu)造函數(shù)的特點(diǎn)和new基本原理進(jìn)行一個梳理洞渤。
上面代碼中阅嘶,首先,我們創(chuàng)建了一個構(gòu)造函數(shù)Person载迄,傳入了兩個參數(shù)name和height讯柔。構(gòu)造函數(shù)Person內(nèi)部使用了this關(guān)鍵字來指向?qū)⒁傻膶ο髮?shí)例。
然后护昧,我們使用new命令來創(chuàng)建了兩個對象實(shí)例boy和girl磷杏。
當(dāng)我們使用new來調(diào)用構(gòu)造函數(shù)時,new命令會創(chuàng)建一個空對象boy捏卓,作為將要返回的實(shí)例對象极祸。接著,這個空對象的原型會指向構(gòu)造函數(shù)Person的prototype屬性怠晴。也就是boy.prototype===Person.prototype的遥金。要注意的是空對象指向構(gòu)造函數(shù)Person的prototype屬性,而不是指向構(gòu)造函數(shù)本身蒜田。然后稿械,我們將這個空對象賦值給構(gòu)造函數(shù)內(nèi)部的this關(guān)鍵字。也就是說冲粤,讓構(gòu)造函數(shù)內(nèi)部的this關(guān)鍵字指向一個對象實(shí)例美莫。最后,開始執(zhí)行構(gòu)造函數(shù)內(nèi)部代碼梯捕。
因?yàn)閷ο髮?shí)例boy和girl是沒有name和height屬性的厢呵,所以對象實(shí)例中的兩個屬性都是繼承自構(gòu)造函數(shù)Person中的。這也就說明了構(gòu)造函數(shù)是生成對象的函數(shù)傀顾,是給對象提供模板的函數(shù)襟铭。
一個問題,如果我們忘記使用new命令來調(diào)用構(gòu)造函數(shù),直接調(diào)用構(gòu)造函數(shù)了寒砖,會發(fā)生什么赐劣?
這種情況下,構(gòu)造函數(shù)就變成了普通函數(shù)哩都,并不會生成實(shí)例對象魁兼。而且由于后面會說到的原因,this這時代表全局對象漠嵌,將造成一些意想不到的結(jié)果咐汞。
function Keith() {
? ? ? this.height = 180;
}
var person = Keith();
console.log(person.height); //TypeError: person is undefined
console.log(window.height); //180
上面代碼中,當(dāng)在調(diào)用構(gòu)造函數(shù)Keith時献雅,忘記加上new命令碉考。結(jié)果是this指向了全局作用域塌计,height也就變成了全局變量挺身。而變量person變成了undefined。
因此锌仅,應(yīng)該非常小心章钾,避免出現(xiàn)不使用new命令、直接調(diào)用構(gòu)造函數(shù)的情況热芹。
為了保證構(gòu)造函數(shù)必須與new命令一起使用贱傀,一個解決辦法是,在構(gòu)造函數(shù)內(nèi)部使用嚴(yán)格模式伊脓,即第一行加上use strict府寒。
?function Person(name, height) {
? ? ? ?'use strict';
? ? ? this.name = name;
? ? ? ?this.height = height;
}
var boy = Person();
console.log(boy) //TypeError: name is undefined
上面代碼的Person為構(gòu)造函數(shù),use strict命令保證了該函數(shù)在嚴(yán)格模式下運(yùn)行报腔。由于在嚴(yán)格模式中株搔,函數(shù)內(nèi)部的this不能指向全局對象。如果指向了全局纯蛾,this默認(rèn)等于undefined纤房,導(dǎo)致不加new調(diào)用會報錯(JavaScript不允許對undefined添加屬性)。
另一個解決辦法翻诉,是在構(gòu)造函數(shù)內(nèi)部判斷是否使用new命令炮姨,如果發(fā)現(xiàn)沒有使用,則直接返回一個實(shí)例對象碰煌。
function Person(name, height) {
if (!(this instanceof Person)) {
? ? ? ? ? return new Person(name, height);
?}
this.name = name;
this.height = height;
}
var boy = Person('Keith');
console.log(boy.name) //'Keith'
上面代碼中的構(gòu)造函數(shù)舒岸,不管加不加new命令,都會得到同樣的結(jié)果芦圾。
如果構(gòu)造函數(shù)內(nèi)部有return語句吁津,而且return后面跟著一個復(fù)雜數(shù)據(jù)類型(對象,數(shù)組等),new命令會返回return語句指定的對象碍脏;如果return語句后面跟著一個簡單數(shù)據(jù)類型(字符串梭依,布爾值,數(shù)字等)典尾,則會忽略return語句役拴,返回this對象。
function Keith() {
this.height = 180;
return {
? ? ? ? ?height: 200
};
}
var boy = new Keith();
?console.log(boy.height); //200
function Keith() {
this.height = 100;
? ? ? ?return 200;
}
var boy = new Keith();
console.log(boy.height); //100
另一方面钾埂,如果對普通函數(shù)(內(nèi)部沒有this關(guān)鍵字的函數(shù))使用new命令河闰,則會返回一個空對象。
function Keith() {
? ? ?return 'this is a message';
}
var boy = new Keith();
console.log(boy); // Keith {}
上面代碼中褥紫,對普通函數(shù)Keith使用new命令姜性,會創(chuàng)建一個空對象。這是因?yàn)閚ew命令總是返回一個對象髓考,要么是實(shí)例對象部念,要么是return語句指定的對象或數(shù)組。本例中氨菇,return語句返回的是字符串儡炼,所以new命令就忽略了該語句。
構(gòu)造函數(shù)的繼承
1查蓉、構(gòu)造函數(shù)綁定:使用call或apply方法乌询,將父對象的構(gòu)造函數(shù)綁定在子對象上。
2豌研、prototype模式:使用prototype屬性瓣距。