JS面向對象之繼承——原型鏈

原型對象

  每一個javascript對象都有一個原型對象,這個對象在不一樣的解釋器下的實現不一樣。好比在firefox下,每一個對象都有一個隱藏的__proto__屬性,這個屬性就是「原型對象」的引用。javascript

原型鏈

  因爲原型對象自己也是對象,根據上邊的定義,它也有本身的原型,而它本身的原型對象又能夠有本身的原型,這樣就組成了一條鏈,這個就是原型鏈,JavaScritp引擎在訪問對象的屬性時,若是在對象自己中沒有找到,則會去原型鏈中查找,若是找到,直接返回值,若是整個鏈都遍歷且沒有找到屬性,則返回undefined.原型鏈通常實現爲一個鏈表,這樣就能夠按照必定的順序來查找。java

 

繼承是OO語言中一個重要的特性和概念。許多的OO語言中都支持兩種繼承方式:接口繼承和實現繼承。數組

ECMAScript只支持實現繼承,其實現繼承主要是靠原型鏈來實現。在PHP語言中,是使用extend來實現繼承。那麼咱們就先來說講原型鏈。函數

原型鏈的基本思想是利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。this

簡單回顧下構造函數、原型和實例的關係:spa

每一個構造函數都有一個原型對象,原型對象包含一個指向構造函數的指針(prototype),而實例則包含一個指向原型對象的內部指針(__proto__)。firefox

實現原型鏈有一種基本模式,其代碼大體以下:prototype

   function SuperType() {
        this.property = true;
    }

    SuperType.prototype.getSuperValue = function() {
      return this.property;
    };

    function SubType() {
        this.subproperty = false;
    }

    //繼承了SuperType
    SubType.prototype = new SuperType();
    SubType.prototype.getSubValue = function() {
        return this.subproperty;
    };

    var instance = new SubType();
    alert(instance.getSubValue()); //false

以上代碼是定義了2個類型:SuperType()和SubType(),每一個類型分別有一個屬性和方法。2者的區別是SubType繼承了SuperType。經過建立SuperType實例並將該實例賦給SubType.prototype。原來存在於SuperType中全部的屬性和方法也都存在於SubType.prototype中了。在確立了這種繼承關係後,又在SubType.prototype中添加了一個方法。指針

請看下圖展現的實例以及構造函數和原型之間的關係:PS:找線畫了半天沒畫好,先這麼看吧:)code

肯定原型和實例的關係:

能夠經過兩種方式來肯定原型和實例之間的關係。第一種方式是使用instanceof操做符;第二種是使用isPrototypeOf()方法。

alert(instance instanceof Object); //true
alert(instance instanceof SuperType); //true
alert(instance instanceof SubType); //true

alert(Object.prototype.isPrototypeOf(instance)); //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance)); //true

原型鏈的問題:

 雖然很強大,能夠用它來實現繼承,但它也存在一些問題。最主要的問題來自包含引用類型值的原型。在經過原型來實現繼承時,原型實際上會變成一個類型的實例。因而,原先的實例屬性也瓜熟蒂落的變成了如今的原型的屬性了。看例子吧!

雖然很強大,能夠用它來實現繼承,但它也存在一些問題。最主要的問題來自包含引用類型值的原型。在經過原型來實現繼承時,原型實際上會變成一個類型的實例。因而,原先的實例屬性也瓜熟蒂落的變成了如今的原型的屬性了。看例子吧!

    function SuperType() {
        this.colors = ["red", "green", "blue"];
    }

    function SubType() {
    }

    //繼承了SuperType
    SubType.prototype = new SuperType();
    var instance1 = new SubType();
    instance1.colors.push("black");
    alert(instance1.colors); //red,green,blue,black

    var instance2 = new SubType();
    alert(instance2.colors); //red,green,blue,black

SuperType構造函數定義了一個屬性,該屬性包含一個數組(引用類型值)。當SubType經過原型繼承了SuperType以後,SubType.prototype就變成了SuperType的一個實例。所以也擁有了SuperType的全部屬性和方法。結果SubType會共享這個colors屬性,咱們經過對instance1.colors的修改,可以經過instance2.colors反映出來。

第二個問題是建立子類型的實例時,不能向超類型的構造函數中傳遞函數。鑑於這幾點問題,實踐中不多會單獨使用原型鏈。

hasOwnProperty函數

hasOwnProperty是判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性,是JS中惟一一個查找屬性,但不查找原型鏈的函數。

相關文章
相關標籤/搜索