最詳細的JavaScript高級教程(十七)原型鏈

概述

首先說明,學習原型鏈的知識是爲了更好的理解原型和原型對象,在實際應用中很少單獨使用下面介紹的原型鏈,具體的原因是下面提到的它的缺點。

我們複習一下之前的知識:

  • 構造函數的prototype指向了原型對象
  • 原型對象中constructor指向了構造函數
  • 實例中的__proto__指向了原型對象

這時候我們如果將一個實例的原型指針,指向另一個對象的實例,這時候這些實例就會串成一個鏈條,即A實例的__proto__指向B實例,B實例的__proto__又指向其原型對象。下面的代碼是原型鏈的基本實現:

  function SuperType() {
    this.property = true;
  }
  SuperType.prototype.getSuperValue = function() {
    return this.property;
  };
  function SubType() {
    this.subProperty = false;
  }
  SubType.prototype = new SuperType(); //將SubType的原型對象指向SuperType的實例
  SubType.prototype.getSubValue = function() {
    return this.subProperty;
  };
  var instance = new SubType();
  alert(instance.getSuperValue()); // true

其繼承關係如下圖
在這裏插入圖片描述
注意,SubType的prototype指向SuperType的一個實例,所以SubType的prototype的prototype就指向了SuperType的prototype。(理解清楚,有點繞口)

爲了強化這個概念,我們看一個問題,在上面的代碼中,instance的constructor屬性指向誰呢?答案是指向SuperType的構造函數。爲什麼呢?我們來分析一下:

  1. 在原型鏈中SubType的prototype指向SuperType的一個實例
  2. 實例並沒有constructor屬性,這個屬性是在prototype中的,原型對象中的這個屬性指向了構造函數
  3. instance沒有constructor,要從原型對象中獲得constructor
  4. 其原型對象是SuperType的一個實例,這個實例也沒有constructor,要從自己的prototype中獲得
  5. 從SuperType的一個實例的prototype中獲得的constructor就是SuperType的構造函數

默認原型Object

我們之前說過,如果寫了一個構造函數,就會創建一個默認的原型對象,現在我們學習了原型鏈之後我們就能進一步完整這個理解。

創建的默認的原型對象的prototype指向Object,從Object中繼承了toString ValueOf等方法。所以完整的原型鏈如下如:
在這裏插入圖片描述
注意SuperType的prototype指向Object,而SubType的prototype原本也指向Object,我們將其指向了Supertype的實例,實現了原型鏈。

注意在上面的圖中,SubType Prototype其實就是SuperType的一個實例,所以它的Prototype才指向了SuperType的Prototype,同理,Supertype Prototype也是Object的一個實例。

對象識別

  • instanceof 這個操作符可以判斷實例的任意一個父構造函數
    alert(instance instanceof Object); //true
    alert(instance instanceof SuperType); //true
    alert(instance instanceof SubType); //true
    
  • isPrototypeOf 判斷實例的原型,任意在鏈上的原型都可以
    alert(Object.prototype.isPrototypeOf(instance)); //true
    alert(SubType.prototype.isPrototypeOf(instance)); //true
    alert(SuperType.prototype.isPrototypeOf(instance)); //true
    

複寫方法

注意複寫方法一定要在替換原型對象之後,這個也很好理解,因爲我們在替換了原型對象之後,指針就改變了。

原型鏈的問題

  1. 實例不復寫直接使用原型中的引用類型屬性,這個屬性會在所有的實例中共享。這是我們不希望看到的。
    function SuperType() {
        this.property = ['red'];
    }
    function SubType() {}
    SubType.prototype = new SuperType(); //將SubType的原型對象指向SuperType的實例
    var instance = new SubType();
    instance.property.push('blue');
    var ins2 = new SubType();
    alert(ins2.property); //red,blue 無法各自擁有自己的,原先屬於原型對象的引用類型
    
  2. 創建子類型的時候不能向超類型的構造函數中傳遞參數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章