javascript面向對象編程學習(三) —— 構造函數繼承和組合繼承

導讀

javascript面向對象編程學習(一)
javascript面向對象編程學習(二) —— 原型鏈繼承javascript

1、借用構造函數繼承

一、 如何實現借用構造函數繼承?

利用call()apply()方法,在子構造函數Child()中,調用Person.call(this, name),加強子構造函數實例;實質等同於複製父實例給子函數。java

1.1代碼實現

function Person(name) {
     this.name = name;
     this.names = ['大魔王','魔鬼', '惡魔'];
     this.getName = function () {
         console.log(this.name)
     }
   }
  Person.prototype.say = function (){
     console.log('my name is ' + this.name);
   }
   
   function Child(name, age){
     // 繼承Person
     Person.call(this, name);
     this.age = age;
   }
   
   var child = new Child('小魔王', 22);
   var child1  = new Child('大魔王', 25);
   console.log(child.names);   // ["大魔王", "魔鬼", "惡魔"]
   console.log(child1.names);  // ["大魔王", "魔鬼", "惡魔"]
   
   child.names.push('小魔王'); 
   
   console.log(child.names);   // ["大魔王", "魔鬼", "惡魔", "小魔王"]
   console.log(child1.names);  // ["大魔王", "魔鬼", "惡魔"]
   
   console.log(child.name);    // 小魔王
   console.log(child.age);     // 22
複製代碼

二、爲何能夠用call()apply()方法來實現繼承?

首先,咱們要了解一下call的定義:調用一個對象的一個方法,以另外一個對象替換當前對象。
也就是說,當執行Person.call(this, name)的時候,實質就是Personthis指向了Child
所以,實例child也有了Person的屬性和方法了,也就實現了繼承!編程

三、關係圖以下:

借用構造函數繼承

四、缺點:

  1. 只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法;
    Personthis指向了Child, 也就是說,Child只是複製了Person的屬性和方法,原型鏈並無和它產生關係;child實例的__proto__仍是指向Child。以下:
    構造函數繼承2
  2. 沒法實現構造函數的複用,每一個子類都有父類實例函數的副本,影響性能,代碼會臃腫。

2、 組合繼承

一、什麼是組合繼承?

原型鏈繼承構造函數繼承優勢組合起來。使用構造函數繼承實現對實例上的屬性和和方法繼承,使用原型鏈繼承實現對原型上的屬性和方法的繼承。這樣就能使在原型上定義的方法可以實現函數複用,而且沒個實例也有本身的屬性。app

二、代碼實現

function Person(name) {
     this.name = name;
	 this.names = ['大魔王','魔鬼', '惡魔'];
   }
   
   Person.prototype.sayName = function (){
     console.log('my name is:' + this.name);
   }
   
   function Child(name, age){
     // 繼承Person實例屬性
     Person.call(this,name);
	 this.age = age;
   }
   
   // 繼承原型的屬性和方法
   Child.prototype = new Person();
   Child.prototype.constructor = Child; // 由於原型鏈繼承,會把constructor指向改變,因此要從新指回自身
   Child.prototype.sayAge = function (){
     console.log('my age is:' + this.age);
   }
   
   
   const child = new Child('小魔王', 22);
   child.names.push('人');
   child.sayName();             // my name is:小魔王
   child.sayAge();              // my age is:22
   console.log(child.names);    // ["大魔王", "魔鬼", "惡魔", "人"]
   
   const child2 = new Child('人', 28);
   child2.sayName();            // my name is:人
   child2.sayAge();             // my age is:28
   console.log(child2.names);   // ["大魔王", "魔鬼", "惡魔"]
複製代碼

三、關係圖以下:

組合繼承

四、缺點

父類實例的屬性和方法既存在於子類的實例中也存在於原型中。以下圖:函數

組合繼承2

3、 總結

想要弄清楚構造函數繼承,要先弄明白call()apply()方法的定義和使用,要清楚this指向。
組合繼承,當你弄清楚原型鏈繼承和構造函數繼承,而後再把二者結合去思考,就天然而然懂了。
學習的最好的辦法仍是實踐;就譬如我這樣動起手來,畫圖和敲代碼等等,比只看而不去動手,要了解得更加透徹!
你的贊是對我最大的支持,也是我最大的動力!post

相關文章
相關標籤/搜索