理解Javascript_05_原型繼承原理

作者: 笨蛋的座右銘  來源: 博客園  發布時間: 2010-10-18 21:30  閱讀: 1055 次  推薦: 0   原文鏈接   [收藏]  

  對于面向對象的基礎語法在此我就不重復了,對面向對象不熟悉的朋友可以參看《使用面向對象的技術創建高級 Web 應用程序》一文。

  prototype與[[prototype]]

  在有面象對象基礎的前提下,來看一段代碼:

//Animal構造函數
function Animal(name){
	this.name = name;
}
//Animal原型對象
Animal.prototype = {
	id:"Animal",
	sleep:function(){
		alert("sleep");
	}
}

var dog = new Animal("旺才");
alert(dog.name);//旺才
alert(dog.id);//Animal
dog.sleep()//sleep

  其對應的簡易內存分配結構圖:

 

  現在讓我們來解釋一下這張內存圖的來龍去脈:

  首先明確一點[[prototype]]與prototype并不是同一個東西。那先來看prototype,每一個函數對象都有一個顯示的prototype屬性,它代表了對象的原型,更明確的說是代表了由函數對象(構造函數)所創建出來的對象的原型。結合本例,Animal.prototype就是dog的原型,dog所引用的那個對象將從Animal.prototype所引用的對象那繼承屬性與方法。

  每個對象都有一個名為[[Prototype]]的內部屬性,指向于它所對應的原型對象。在本例中dog的[[prototype]]指向Animal.prototype,大家都知道,Animal.prototype也是一個對象,即然是一個對象,那它必然也有[[prototype]]屬性指向于它所對應的原型對象,由此便構成了一種鏈表的結構,這就是原型鏈的概念。額外要說的是:不同的JS引擎實現者可以將內部[[Prototype]]屬性命名為任何名字,并且設置它的可見性,前且只在JS引擎內部使用。雖然無法在JS代碼中訪問到內部[[Prototype]](FireFox中可以,名字為__proto__因為Mozilla將它公開了),但可以使用對象的 isPrototypeOf()方法進行測試,注意這個方法會在整個Prototype鏈上進行判斷。

注:關于函數對象的具體內容,將在后繼的博文中講解。

  屬性訪問原則

  使用obj.propName訪問一個對象的屬性時,按照下面的步驟進行處理(假設obj的內部[[Prototype]]屬性名為__proto__):

  1. 如果obj存在propName屬性,返回屬性的值,否則

  2. 如果obj.__proto__為null,返回undefined,否則

  3. 返回obj.__proto__.propName

  調用對象的方法跟訪問屬性搜索過程一樣,因為方法的函數對象就是對象的一個屬性值。

  提示: 上面步驟中隱含了一個遞歸過程,步驟3中obj.__proto__是另外一個對象,同樣將采用1, 2, 3這樣的步驟來搜索propName屬性。

  這就是基于Prototype的繼承和共享。其中object1的方法fn2來自object2,概念上即object2重寫了object3的方法fn2。JavaScript對象應當都通過prototype鏈關聯起來,最頂層是Object,即對象都派生自Object類型。

  結合是上面的理論,讓我們再來看一個更加復雜的示例,他明確的解釋了prototype、[[prototype]]、原型鏈以及屬性訪問的相關要點:

//Animal構造函數
function Animal(name){
	this.name = name;
}
//Animal原型對象
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相關調用
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

  根據上面的代碼,你能畫出相應的內存圖嗎?好,讓我們來看一下:

  注:prototype的根為Object.prototype,對象Object.prototype的內部[[prototype]]屬性為null。其實,這里還有很多東西可以講,但在其原理都在這張圖上了,可試著調整一下代碼的次序,如將Human.prototype.id = "Human";放在Human.prototype = new Animal();的前面,看一下運行結果,解釋一下為什么之類的,你可以學到很多。

  我發現,通過內存來展現程序內部運行細節真的是太完美了!

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()