在使用物件導向編程時,對象間的繼承關係自然少不了!而原型正是實現javascript繼承的很重要的一種方法!
我們首先來看以下代碼:
複製代碼 代碼如下:
function person(name, age) {
this.name = name;
this.age = age;
}
person.prototype.getInfo = function() {
alert("My name is "+this.name+", and I have "+this.age+" years old");
}
var zhangchen = new person("zhangchen", 23);
zhangchen.getInfo(); //output My name is zhangchen, and I have 23 years old;
從啟動並執行結果我們可以看出,通過關鍵字new建立的zhangchen這個對象繼承了person中通過原型定義的getInfo()方法。下面我們具體來看建立的zhangchen這個對象是如何繼承person對象的屬性和方法的。
原型:在使用 JavaScript 的物件導向編程中,原型對象是個核心概念。在 JavaScript 中對象是作為現有樣本(即原型)對象的副本而建立的,該名稱就來自於這一概念。此原型對象的任何屬性和方法都將顯示為從原型的建構函式建立的對象的屬性和方法。可以說,這些對象從其原型繼承了屬性和方法。當建立zhangchen對象時:
複製代碼 代碼如下:
var zhangchen = new company("zhangchen", 23);
zhangchen 所引用的對象將從它的原型繼承屬性和方法,對象 zhangchen 的原型來自建構函式(在這裡是函數 person)的屬性。
在 JavaScript 中,每個函數都有名為prototype的屬性,用於引用原型對象。此原型對象又有名為constructor的屬性,它反過來引用函數本身。這是一種循環參考, 更好地說明了這種迴圈關係。
圖1 迴圈關係
現在,通過new運算子用函數(上面樣本中為 person)建立對象時,所獲得的對象將繼承 person.prototype 的屬性。在,可以看到 person.prototype 對象有一個回指 person 函數的建構函式屬性。這樣,每個 person對象(從 person.prototype 繼承而來)都有一個回指 person 函數的建構函式屬性。
我們可以用以下代碼來驗證這種迴圈是否正確:
複製代碼 代碼如下:
function person(name, age) {
this.name = name;
this.age = age;
}
person.prototype.getInfo = function() {
alert("My name is "+this.name+", and I have "+this.age+" years old");
}
var zhangchen = new person("zhangchen", 23);
alert(zhangchen.constructor == person.prototype.constructor); //output true
alert(zhangchen.constructor == person);// output true
alert(person.prototype.isPrototypeOf(zhangchen)); //output true
以上代碼中的對"isPrototypeOf()"方法的調用來自哪裡呢?是來自person.prototype對象嗎?不對,實際上,在 person.prototype 和 person 執行個體中還可以調用其他方法,比如 toString、toLocaleString 和 valueOf,但它們都不來自 person.prototype。而是來自於JavaScript 中的 Object.prototype ,它是所有原型的最終基礎原型。(Object.prototype 的原型是 null。)
在以上例中,zhangchen.prototype 是對象。它是通過調用 Object 建構函式建立的(儘管它不可見)相當於執行子以下代碼:
複製代碼 代碼如下:
zhangchen.prototype = new Object();
因此,正如 person執行個體繼承person.prototype 一樣,zhangchen.prototype 繼承 Object.prototype。這使得所有 zhangchen 執行個體也繼承了 Object.prototype 的方法和屬性。
原型鏈:每個 JavaScript 對象都繼承一個原型鏈,而所有原型都終止於 Object.prototype。注意,這種繼承是使用中的物件之間的繼承。它不同於繼承的常見概念,後者是指在聲明類時類之間的發生的繼承。因此,JavaScript 繼承動態性更強。它使用簡單演算法實現這一點,如下所示:當您嘗試訪問對象的屬性/方法時,JavaScript 將檢查該屬性/方法是否是在該對象中定義的。如果不是,則檢查對象的原型。如果還不是,則檢查該對象的原型的原型,如此繼續,一直檢查到 Object.prototype。說明了此解析過程:
圖2 toString()方法的解析過程
從以上解析過程中,如果在對象中定義了屬性/方法 X,則該對象的原型中將隱藏同名的屬性/方法。例如,通過在 person.prototype 中定義 toString 方法,可以改寫 Object.prototype 的 toString 方法。
再看以下代碼:
複製代碼 代碼如下:
function person(name, age) {
this.name = name;
this.age = age;
}
person.prototype.getInfo = function() {
alert("My name is "+this.name+", and I have "+this.age+" years old");
}
var zhangchen = new person("zhangchen", 23);
var luomi = new person("luomi", 23);
zhangchen.getInfo(); // output My name is zhangchen, and I have 23 years old;
luomi.getInfo(); // output My name is luomi, and I have 23 years old;
luomi.getInfo = function() {
alert("here can rewrite the function of getInfo!");
}
luomi.getInfo(); //here can rewrite the function of getInfo!
zhangchen.getInfo(); // output My name is zhangchen, and I have 23 years old;
從運行結果可以看到,雖然person的每個執行個體都繼承了person.prototype中的方法,但是我們也可以在執行個體化的對象中重新定義原型對象中的方法,而且也不會影響到其它的執行個體!
以上是自己對原型及原型鏈繼承方式的認識,參考( JavaScript: 使用物件導向的技術建立進階 Web 應用程式),希望大家共同討論!