理解Javascript_05_原型繼承原理
更新時(shí)間:2010年10月13日 19:34:16 作者:
對(duì)于面向?qū)ο蟮幕A(chǔ)語法在此我就不重復(fù)了,對(duì)面向?qū)ο蟛皇煜さ呐笥芽梢詤⒖础妒褂妹嫦驅(qū)ο蟮募夹g(shù)創(chuàng)建高級(jí) Web 應(yīng)用程序》一文。
prototype與[[prototype]]
在有面象對(duì)象基礎(chǔ)的前提下,來看一段代碼:
//Animal構(gòu)造函數(shù)
function Animal(name){
this.name = name;
}
//Animal原型對(duì)象
Animal.prototype = {
id:"Animal",
sleep:function(){
alert("sleep");
}
}
var dog = new Animal("旺才");
alert(dog.name);//旺才
alert(dog.id);//Animal
dog.sleep()//sleep
其對(duì)應(yīng)的簡(jiǎn)易內(nèi)存分配結(jié)構(gòu)圖:

現(xiàn)在讓我們來解釋一下這張內(nèi)存圖的來龍去脈:
首先明確一點(diǎn)[[prototype]]與prototype并不是同一個(gè)東西。
那先來看prototype,每一個(gè)函數(shù)對(duì)象都有一個(gè)顯示的prototype屬性,它代表了對(duì)象的原型,更明確的說是代表了由函數(shù)對(duì)象(構(gòu)造函數(shù))所創(chuàng)建出來的對(duì)象的原型。結(jié)合本例,Animal.prototype就是dog的原型,dog所引用的那個(gè)對(duì)象將從Animal.prototype所引用的對(duì)象那繼承屬性與方法。
每個(gè)對(duì)象都有一個(gè)名為[[Prototype]]的內(nèi)部屬性,指向于它所對(duì)應(yīng)的原型對(duì)象。在本例中dog的[[prototype]]指向Animal.prototype,大家都知道,Animal.prototype也是一個(gè)對(duì)象,即然是一個(gè)對(duì)象,那它必然也有[[prototype]]屬性指向于它所對(duì)應(yīng)的原型對(duì)象,由此便構(gòu)成了一種鏈表的結(jié)構(gòu),這就是原型鏈的概念。額外要說的是:不同的JS引擎實(shí)現(xiàn)者可以將內(nèi)部[[Prototype]]屬性命名為任何名字,并且設(shè)置它的可見性,前且只在JS引擎內(nèi)部使用。雖然無法在JS代碼中訪問到內(nèi)部[[Prototype]](FireFox中可以,名字為__proto__因?yàn)镸ozilla將它公開了),但可以使用對(duì)象的 isPrototypeOf()方法進(jìn)行測(cè)試,注意這個(gè)方法會(huì)在整個(gè)Prototype鏈上進(jìn)行判斷。
注:關(guān)于函數(shù)對(duì)象的具體內(nèi)容,將在后繼的博文中講解。
屬性訪問原則
使用obj.propName訪問一個(gè)對(duì)象的屬性時(shí),按照下面的步驟進(jìn)行處理(假設(shè)obj的內(nèi)部[[Prototype]]屬性名為__proto__):
1. 如果obj存在propName屬性,返回屬性的值,否則
2. 如果obj.__proto__為null,返回undefined,否則
3. 返回obj.__proto__.propName
調(diào)用對(duì)象的方法跟訪問屬性搜索過程一樣,因?yàn)榉椒ǖ暮瘮?shù)對(duì)象就是對(duì)象的一個(gè)屬性值。
提示: 上面步驟中隱含了一個(gè)遞歸過程,步驟3中obj.__proto__是另外一個(gè)對(duì)象,同樣將采用1, 2, 3這樣的步驟來搜索propName屬性。

這就是基于Prototype的繼承和共享。其中object1的方法fn2來自object2,概念上即object2重寫了object3的方法fn2。
JavaScript對(duì)象應(yīng)當(dāng)都通過prototype鏈關(guān)聯(lián)起來,最頂層是Object,即對(duì)象都派生自O(shè)bject類型。
結(jié)合是上面的理論,讓我們?cè)賮砜匆粋€(gè)更加復(fù)雜的示例,他明確的解釋了prototype、[[prototype]]、原型鏈以及屬性訪問的相關(guān)要點(diǎn):
//Animal構(gòu)造函數(shù)
function Animal(name){
this.name = name;
}
//Animal原型對(duì)象
Animal.prototype = {
id:"Animal",
sleep:function(){
alert("sleep");
}
}
function Human(name,age){
Animal.call(this,name);
this.age = age;
}
Human.prototype = new Animal();
Human.prototype.id = "Human";
Human.prototype.say = function(){
alert("hello everyone,My name is "+this.name +",I'm "+this.age+" and I'm a "+this.id);
}
//Human相關(guān)調(diào)用
var jxl = new Human('笨蛋',25);
alert(jxl.name);//笨蛋
alert(jxl.id);//Human
jxl.say();//hello everyone,My name is 笨蛋,I'm 25 and I'm a Human
alert(Animal.prototype.isPrototypeOf(jxl));//true
alert(Object.prototype.isPrototypeOf(jxl));//true
根據(jù)上面的代碼,你能畫出相應(yīng)的內(nèi)存圖嗎?好,讓我們來看一下:

注:prototype的根為Object.prototype,對(duì)象Object.prototype的內(nèi)部[[prototype]]屬性為null.
其實(shí),這里還有很多東西可以講,但在其原理都在這張圖上了,可試著調(diào)整一下代碼的次序,如將Human.prototype.id = "Human";放在Human.prototype = new Animal();的前面,看一下運(yùn)行結(jié)果,解釋一下為什么之類的,你可以學(xué)到很多。
我發(fā)現(xiàn),通過內(nèi)存來展現(xiàn)程序內(nèi)部運(yùn)行細(xì)節(jié)真的是太完美了!
在有面象對(duì)象基礎(chǔ)的前提下,來看一段代碼:
復(fù)制代碼 代碼如下:
//Animal構(gòu)造函數(shù)
function Animal(name){
this.name = name;
}
//Animal原型對(duì)象
Animal.prototype = {
id:"Animal",
sleep:function(){
alert("sleep");
}
}
var dog = new Animal("旺才");
alert(dog.name);//旺才
alert(dog.id);//Animal
dog.sleep()//sleep
其對(duì)應(yīng)的簡(jiǎn)易內(nèi)存分配結(jié)構(gòu)圖:

現(xiàn)在讓我們來解釋一下這張內(nèi)存圖的來龍去脈:
首先明確一點(diǎn)[[prototype]]與prototype并不是同一個(gè)東西。
那先來看prototype,每一個(gè)函數(shù)對(duì)象都有一個(gè)顯示的prototype屬性,它代表了對(duì)象的原型,更明確的說是代表了由函數(shù)對(duì)象(構(gòu)造函數(shù))所創(chuàng)建出來的對(duì)象的原型。結(jié)合本例,Animal.prototype就是dog的原型,dog所引用的那個(gè)對(duì)象將從Animal.prototype所引用的對(duì)象那繼承屬性與方法。
每個(gè)對(duì)象都有一個(gè)名為[[Prototype]]的內(nèi)部屬性,指向于它所對(duì)應(yīng)的原型對(duì)象。在本例中dog的[[prototype]]指向Animal.prototype,大家都知道,Animal.prototype也是一個(gè)對(duì)象,即然是一個(gè)對(duì)象,那它必然也有[[prototype]]屬性指向于它所對(duì)應(yīng)的原型對(duì)象,由此便構(gòu)成了一種鏈表的結(jié)構(gòu),這就是原型鏈的概念。額外要說的是:不同的JS引擎實(shí)現(xiàn)者可以將內(nèi)部[[Prototype]]屬性命名為任何名字,并且設(shè)置它的可見性,前且只在JS引擎內(nèi)部使用。雖然無法在JS代碼中訪問到內(nèi)部[[Prototype]](FireFox中可以,名字為__proto__因?yàn)镸ozilla將它公開了),但可以使用對(duì)象的 isPrototypeOf()方法進(jìn)行測(cè)試,注意這個(gè)方法會(huì)在整個(gè)Prototype鏈上進(jìn)行判斷。
注:關(guān)于函數(shù)對(duì)象的具體內(nèi)容,將在后繼的博文中講解。
屬性訪問原則
使用obj.propName訪問一個(gè)對(duì)象的屬性時(shí),按照下面的步驟進(jìn)行處理(假設(shè)obj的內(nèi)部[[Prototype]]屬性名為__proto__):
1. 如果obj存在propName屬性,返回屬性的值,否則
2. 如果obj.__proto__為null,返回undefined,否則
3. 返回obj.__proto__.propName
調(diào)用對(duì)象的方法跟訪問屬性搜索過程一樣,因?yàn)榉椒ǖ暮瘮?shù)對(duì)象就是對(duì)象的一個(gè)屬性值。
提示: 上面步驟中隱含了一個(gè)遞歸過程,步驟3中obj.__proto__是另外一個(gè)對(duì)象,同樣將采用1, 2, 3這樣的步驟來搜索propName屬性。

這就是基于Prototype的繼承和共享。其中object1的方法fn2來自object2,概念上即object2重寫了object3的方法fn2。
JavaScript對(duì)象應(yīng)當(dāng)都通過prototype鏈關(guān)聯(lián)起來,最頂層是Object,即對(duì)象都派生自O(shè)bject類型。
結(jié)合是上面的理論,讓我們?cè)賮砜匆粋€(gè)更加復(fù)雜的示例,他明確的解釋了prototype、[[prototype]]、原型鏈以及屬性訪問的相關(guān)要點(diǎn):
復(fù)制代碼 代碼如下:
//Animal構(gòu)造函數(shù)
function Animal(name){
this.name = name;
}
//Animal原型對(duì)象
Animal.prototype = {
id:"Animal",
sleep:function(){
alert("sleep");
}
}
function Human(name,age){
Animal.call(this,name);
this.age = age;
}
Human.prototype = new Animal();
Human.prototype.id = "Human";
Human.prototype.say = function(){
alert("hello everyone,My name is "+this.name +",I'm "+this.age+" and I'm a "+this.id);
}
//Human相關(guān)調(diào)用
var jxl = new Human('笨蛋',25);
alert(jxl.name);//笨蛋
alert(jxl.id);//Human
jxl.say();//hello everyone,My name is 笨蛋,I'm 25 and I'm a Human
alert(Animal.prototype.isPrototypeOf(jxl));//true
alert(Object.prototype.isPrototypeOf(jxl));//true
根據(jù)上面的代碼,你能畫出相應(yīng)的內(nèi)存圖嗎?好,讓我們來看一下:

注:prototype的根為Object.prototype,對(duì)象Object.prototype的內(nèi)部[[prototype]]屬性為null.
其實(shí),這里還有很多東西可以講,但在其原理都在這張圖上了,可試著調(diào)整一下代碼的次序,如將Human.prototype.id = "Human";放在Human.prototype = new Animal();的前面,看一下運(yùn)行結(jié)果,解釋一下為什么之類的,你可以學(xué)到很多。
我發(fā)現(xiàn),通過內(nèi)存來展現(xiàn)程序內(nèi)部運(yùn)行細(xì)節(jié)真的是太完美了!
相關(guān)文章
Javascript json object 與string 相互轉(zhuǎn)換的簡(jiǎn)單實(shí)現(xiàn)
下面小編就為大家?guī)硪黄狫avascript json object 與string 相互轉(zhuǎn)換的簡(jiǎn)單實(shí)現(xiàn)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-09-09分享一個(gè)自己寫的table表格排序js插件(高效簡(jiǎn)潔)
在前不久做的一個(gè)web項(xiàng)目中,需要實(shí)現(xiàn)js表格排序的效果,當(dāng)時(shí)為了省事,就在網(wǎng)上找了幾個(gè)相關(guān)的js插件2011-10-10效率高的Javscript字符串替換函數(shù)的benchmark
這是經(jīng)常使用的HTML特殊字符替換函數(shù),即將 &、<、>、" 等函數(shù)替換成 &、<、>、"。通常的作法都是連續(xù)使用數(shù)個(gè) replace 函數(shù),而Clear僅使用一個(gè) replace 就完成了替換。2008-08-08js和jquery中循環(huán)的退出和繼續(xù)學(xué)習(xí)記錄
這篇文章主要介紹了js和jquery中循環(huán)的退出和繼續(xù)學(xué)習(xí)記錄,下哦功能不簡(jiǎn)單,需要的朋友可以參考下2014-09-09js實(shí)現(xiàn)ASP分頁函數(shù) HTML分頁函數(shù)
js實(shí)現(xiàn)ASP分頁函數(shù) HTML分頁函數(shù)...2006-09-09javascript作用域鏈與執(zhí)行環(huán)境詳解
這篇文章主要為大家詳細(xì)介紹了javascript作用域鏈與執(zhí)行環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03