JavaScript原型對象、構(gòu)造函數(shù)和實例對象功能與用法詳解
本文實例講述了JavaScript原型對象、構(gòu)造函數(shù)和實例對象功能與用法。分享給大家供大家參考,具體如下:
大家都知道,javascript中其實并沒有類的概念。但是,用構(gòu)造函數(shù)跟原型對象卻可以模擬類的實現(xiàn)。在這里,就先很不嚴謹?shù)氖褂妙愡@個詞,以方便說明。
下面整理了一些關(guān)于javascript的構(gòu)造函數(shù)、原型對象以及實例對象的筆記,有錯誤的地方,望指正。
先用一張圖簡單的概括下這幾者之間的關(guān)系,再細化:

構(gòu)造函數(shù)和實例對象
構(gòu)造函數(shù)是類的外在表現(xiàn),構(gòu)造函數(shù)的名字通常用作類名。
其實構(gòu)造函數(shù)也就是一個函數(shù),只不過它于普通的函數(shù)又有點不同:
- 沒有顯示的創(chuàng)建對象;
- 直接將屬性和方法賦給
this; - 沒有
return語句;
構(gòu)造函數(shù)是用來構(gòu)造新對象的。之前的筆記中有提到過,可以是用new關(guān)鍵詞來調(diào)用構(gòu)造函數(shù),以創(chuàng)建特定類型的新對象。如,創(chuàng)建一個Object類型的對象實例:
var o=new Object();
為了區(qū)別構(gòu)造函數(shù)和普通函數(shù),通常規(guī)定構(gòu)造函數(shù)的命名首字母大寫,而普通函數(shù)的命名首字母小寫。當然,這不是必須的,卻是一個很好的習慣。
通過用構(gòu)造函數(shù)創(chuàng)建并初始化的屬性是實例屬性。所謂的實例屬性就是指,通過該構(gòu)造函數(shù)創(chuàng)建的每個對象,都將擁有一份實例屬性的單獨拷貝。這些屬性都是通過實例來訪問的,值根據(jù)每個實例所定義的為準,若實例中沒有定義,則為構(gòu)造函數(shù)初始化時的默認值。來看一個例子:
function Person(name,age){
this.name=name;
this.age=age;
this.friends=["Tom","Boo"];
}
var p1=new Person("Lily",20);
var p2=new Person("Sam",30);
alert(p1.name); //Lily
alert(p2.name); //Sam
p1.friends.push("Susan");
alert(p1.friends); //Tom,Boo,Susan
alert(p2.friends); //Tom,Boo
上面的例子定義了一個Person構(gòu)造函數(shù),并初始化了name、age和friends三個屬性。接著創(chuàng)建了兩個實例對象,分別為p1和p2。觀察這個例子,每個屬性都是為各自所擁有的,并不會相互影響。這就是因為每個實例對象都擁有一份屬性的副本。
每個實例對象都有一個屬性指向它的構(gòu)造函數(shù),這屬性就是constructor:
function Person(name,age){
this.name=name;
this.age=age;
}
var p1=new Person("Lily",20);
var p2=new Person("Sam",30);
alert(p1.constructor==Person); //true
alert(p2.constructor==Person); //true
構(gòu)造函數(shù)有一個prototype屬性,指向原型對象。
原型對象和實例對象
在javascript中,每個對象都有一個與之相關(guān)聯(lián)的對象,那就是它的原型對象。類的所有實例對象都從它的原型對象上繼承屬性。
原型對象是類的唯一標識:當且僅當兩個對象繼承自同一個原型對象時,它們才是屬于同一個類的實例。
前面有提到,構(gòu)造函數(shù)擁有一個prototype屬性,指向原型。換句話來說,一個對象的原型就是它的構(gòu)造函數(shù)的prototype屬性的值。當一個函數(shù)被定義的時候,它會自動創(chuàng)建和初始化prototype值,它是一個對象,這時這個對象只有一個屬性,那就是constructor,它指回和原型相關(guān)聯(lián)的那個構(gòu)造函數(shù)??磦€例子:
function Person(name,age){
this.name=name;
this.age=age;
}
alert(Person.prototype); //[object Object]
alert(Person.prototype.constructor==Person); //true
也可以通過原型來創(chuàng)建屬性和方法。通過原型創(chuàng)建的屬性和方法是被所有實例所共享的。即,在一個實例中修改了該屬性或方法的值,那么所有其他實例的屬性或方法值都會受到影響:
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.friends=["Tom","Sam"];
var p1=new Person("Lily",24);
var p2=new Person("Susan",20);
alert(p1.friends); //Tom,Sam
alert(p2.friends); //Tom,Sam
p1.friends.push("Bill");
alert(p1.friends); //Tom,Sam,Bill
alert(p2.friends); //Tom,Sam,Bill
由上面的例子可以看出,用原型定義的屬性是被所有實例共享的。為p1添加了一個朋友,導(dǎo)致p2也添加了這個朋友。
其實,很多情況下,這種現(xiàn)象并不是我們想看到的。那么什么時候應(yīng)該用構(gòu)造函數(shù)初始化屬性和方法,哪些時候又該由原型對象來定義呢?
通常建議在構(gòu)造函數(shù)內(nèi)定義一般成員,即它的值在每個實例中都將不同,尤其是對象或數(shù)組形式的值;而在原型對象中則定義一些所有實例所共享的屬性,即在所有實例中,它的值可以是相同的屬性。
當用構(gòu)造函數(shù)創(chuàng)建一個實例時,實例的內(nèi)部也包含了一個指針,指向構(gòu)造函數(shù)的原型對象。一些瀏覽器中,支持一個屬性__proto__來表示這個內(nèi)部指針:
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayName=function(){
alert(this.name);
}
var p1=new Person("Lily",24);
alert(p1.__proto__.sayName); //function (){alert(this.name);}
alert(p1.__proto__.constructor==Person); //true
在ECMAscript5中新增了一個方法,Object.getPrototypeOf(),可以返回前面提到的實例對象內(nèi)部的指向其原型的指針的值:
function Person(name,age){
this.name=name;
this.age=age;
}
var p1=new Person("Lily",24);
alert(Object.getPrototypeOf(p1)==Person.prototype); //true
isPrototypeOf()方法也可用于確定實例對象和其原型之間的這種關(guān)系:
function Person(name,age){
this.name=name;
this.age=age;
}
var p1=new Person("Lily",24);
alert(Person.prototype.isPrototypeOf(p1)); //true
原型語法
從前面介紹原型對象于實例對象及構(gòu)造函數(shù)的關(guān)系中,我們已經(jīng)知道,給原型對象添加屬性和方法只要像這樣定義即可:Person.prototype=name。
那么是否每定義一個Person的屬性,就要敲一遍Person.prototype呢?答案是否定的,我們也可以像用對象字面量創(chuàng)建對象那樣來創(chuàng)建原型對象:
function Person(){
}
Person.prototype={
name:"Tom",
age:29
}
var p1=new Person();
alert(p1.name); //Tom
alert(p1.age); //29
有一點要注意,這個方法相當于重寫了整個原型對象,因此切斷了它與構(gòu)造函數(shù)的關(guān)系,此時Person.prototype.constructor不再指向Person:
function Person(){
}
Person.prototype={
name:"Tom",
age:29
}
var p1=new Person();
alert(Person.prototype.constructor==Person); //false
alert(Person.prototype.constructor==Object); //true
因此,如果想要讓它重新指向Person,可以顯示的進行賦值:
function Person(){
}
Person.prototype={
constructor:Person,
name:"Tom",
age:29
}
var p1=new Person();
alert(Person.prototype.constructor==Person); //true
alert(Person.prototype.constructor==Object); //false
總結(jié)
最后,我們拿一個例子,再來理理構(gòu)造函數(shù)、原型對象以及實例對象之間的關(guān)系:
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayName=function(){
alert(this.name);
}
var p1=new Person("Tom",20);
alert(Person.prototype); //object
alert(Person.prototype.constructor==Person); //true
alert(p1.constructor==Person); //true
alert(p1.__proto__==Person.prototype); //true
alert(p1.__proto__.__proto__==Object.prototype); //true
alert(p1.__proto__.__proto__.constructor==Object); //true
alert(Person.constructor==Function); //true
alert(Object.prototype.constructor==Object);

上圖說明了這個例子中原型、構(gòu)造函數(shù)和實例屬性的關(guān)系。
更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《javascript面向?qū)ο笕腴T教程》、《JavaScript常用函數(shù)技巧匯總》、《JavaScript錯誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運算用法總結(jié)》
希望本文所述對大家JavaScript程序設(shè)計有所幫助。
相關(guān)文章
JavaScript實現(xiàn)倒計時跳轉(zhuǎn)頁面功能【實用】
本文分享了JavaScript實現(xiàn)倒計時跳轉(zhuǎn)頁面功能的具體實例代碼,頁面代碼簡單,直接拷貝就能運行,頁面可以自己美化下哦。需要的朋友一起來看下吧2016-12-12
使用JavaScript實現(xiàn)連續(xù)滾動字幕效果的方法
這篇文章主要介紹了使用JavaScript實現(xiàn)連續(xù)滾動字幕效果的方法,文中給出了瀏覽器端運行的示例腳本,需要的朋友可以參考下2015-07-07
javascript算法解數(shù)獨實現(xiàn)方案示例
這篇文章主要為大家介紹了javascript算法解數(shù)獨實現(xiàn)方案示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08
js前端傳json后臺接收‘‘被轉(zhuǎn)為quot的問題解決
這篇文章主要介紹了js前端傳json后臺接收‘‘被轉(zhuǎn)為"的問題解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2020-11-11

