1. 程式人生 > 其它 >js繼承及原型繼承

js繼承及原型繼承

面向物件程式設計都會涉及到繼承這個概念,JS中實現繼承的方式主要是通過原型鏈的方法。

一、建構函式、原型與例項之間的關係

每建立一個函式,該函式就會自動帶有一個prototype屬性。該屬性是個指標,指向了一個物件,我們稱之為原型物件.。什麼是指標?指標就好比學生的學號,原型物件則是那個學生。我們通過學號找到唯一的那個學生。假設突然,指標設定 null, 學號重置空了,不要慌,物件還存在,學生也沒消失。只是不好找了。

  原型物件上預設有一個屬性constructor,該屬性也是一個指標,指向其相關聯的建構函式。

  通過呼叫建構函式產生的例項,都有一個內部屬性,指向了原型物件。所以例項能夠訪問原型物件上的所有屬性和方法。

所以三者的關係是,每個建構函式都有一個原型物件,原型物件都包含一個指向建構函式的指標,而例項都包含一個指向原型物件的內部指標。通俗點說就是,例項通過內部指標可以訪問到原型物件,原型物件通過constructor指標,又可以找到建構函式。
下面看一個例子:
function Dog (name) {
    this.name = name;
    this.type = 'Dog'; 
}
Dog.prototype.speak = function () {
  alert('wang');
}
var doggie = new Dog('jiwawa');
doggie.speak();  //wang 
以上程式碼定義了一個建構函式 Dog(),  Dog.prototype 指向的原型物件,其自帶的屬性construtor又指回了 Dog,即  Dog.prototype.constructor == Dog. 例項doggie由於其內部指標指向了該原型物件,所以可以訪問到 speak方法。


Dog.prototype 只是一個指標,指向的是原型物件,但是這個原型物件並不特別,它也只是一個普通物件。假設說,這時候,我們讓 Dog.protptype 不再指向最初的原型物件,而是另一個類 (Animal)的例項,情況會怎樣呢?

二、原型鏈

  前面我們說到,所有的例項有一個內部指標,指向它的原型物件,並且可以訪問原型物件上的所有屬性和方法。doggie例項指向了Dog的原型物件,可以訪問Dog原型物件上的所有屬性和方法;如果Dog原型物件變成了某一個類的例項 aaa,這個例項又會指向一個新的原型物件 AAA,那麼 doggie 此時就能訪問 aaa 的例項屬性和 AA A原型物件上的所有屬性和方法了。同理,新的原型物件AAA碰巧又是另外一個物件的例項bbb,這個例項bbb又會指向新的原型物件 BBB,那麼doggie此時就能訪問 bbb 的例項屬性和 BBB 原型物件上的所有屬性和方法了。

  這就是JS通過原型鏈實現繼承的方法了。看下面一個例子:

//定義一個 Animal 建構函式,作為 Dog 的父類
function Animal () {
    this.superType = 'Animal';
}

Animal.prototype.superSpeak = function () {
    alert(this.superType);
}

function Dog (name) {
    this.name = name;
    this.type = 'Dog';  
}
//改變Dog的prototype指標,指向一個 Animal 例項
Dog.prototype = new Animal();
//上面那行就相當於這麼寫
//var animal = new Animal();
//Dog.prototype = animal;

Dog.prototype.speak = function () {
  alert(this.type);
}
var doggie = new Dog('jiwawa');
doggie.superSpeak();  //Animal

  解釋一下。以上程式碼,首先定義了一個 Animal 建構函式,通過new Animal()得到例項,會包含一個例項屬性 superType 和一個原型屬性 superSpeak。另外又定義了一個Dog建構函式。然後情況發生變化,程式碼中加粗那一行,將Dog的原型物件覆蓋成了 animal 例項。當 doggie 去訪問superSpeak屬性時,js會先在doggie的例項屬性中查詢,發現找不到,然後,js就會去doggie 的原型物件上去找,doggie的原型物件已經被我們改成了一個animal例項,那就是去animal例項上去找。先找animal的例項屬性,發現還是沒有 superSpeack, 最後去 animal 的原型物件上去找,誒,這才找到。

  這就說明,我們可以通過原型鏈的方式,實現 Dog 繼承 Animal 的所有屬性和方法。

  總結來說:就是當重寫了Dog.prototype指向的原型物件後,例項的內部指標也發生了改變,指向了新的原型物件,然後就能實現類與類之間的繼承了。(但是如果在重寫原型物件之前,產生的例項,其內部指標指向的還是最初的原型物件