實現繼承的幾種方式及工做原理

  • 原型鏈繼承

    核心:子構造函數的原型指向父構造函數的實例bash

    每一個構造函數都有一個原型對象,原型對象中都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。當原型對象等於另一個類型的實例即繼承。調用某個方法或者屬性的步驟app

    a.搜索實例函數

    b.搜索原型性能

    c.搜索父類原型this

function Animal() {
            this.name = "animal";
            this.arrt = [1, 2]
        }
        Animal.prototype = {
            sayName: function () {
                alert(this.name);
            }
        }

        function Dog() {
            this.color = "灰色"
        }

        Dog.prototype = new Animal();
        Dog.prototype.sayColor = function () {
            alert(this.color);
        }
        var dog = new Dog();
        var dog1 = new Dog();
        console.log(dog);
        dog.arrt.push(5);
        console.log(dog1);
        dog.sayColor();
        dog.sayName();
複製代碼

能夠本身打印一下,看一下結果spa

優勢

1.很是純粹的繼承關係,實例是子類的實例,也是父類的實例prototype

2.父類新增原型方法/原型屬性,子類都能訪問到指針

3.簡單,易於實現code

缺點cdn

1.包含引用類型值的原型屬性會被全部實例共享,這會致使對一個實例的修改會影響另外一個實例。

2.在建立子類型的實例時,不能向超類型的構造函數中傳遞參數。因爲這兩個問題的存在,實踐中不多單獨使用原型鏈。

  • 借用構造函數

    也稱 "僞造對象" 或 "經典繼承",在子類型構造函數的內部調用超類型構造函數。函數不過是在特定環境中執行代碼的對象,所以經過apply(),call()方法能夠在(未來)新建對象上執行構造函數,即 在子類型對象上執行父類型函數中定義的全部對象初始化的代碼。結果每一個子類實例中都具備了父類型中的屬性以及方法

function Animal(name){
	this.name = name;
	this.colors = ["red","gray"];
}
function Dog(name){
	//繼承了Animal
	Animal.call(this,"mary");//在子類型構造函數的內部調用超類型構造函數
	this.color = "gray";
}
Animal.prototype.sayName = function(){
	alert(this.name);
}
 
var dog = new Dog();
var dog1=new Dog();
dog.colors.push("hhh");
console.log(dog.colors);//red gray hhh
console.log(dog1.colors);//red gray
Animal.prototype.swif="hua";
console.log(dog.swif);//undefined
var animal = new Animal();
console.log(animal);   //若是將函數定義在構造函數中,函數複用無從談起
dog.sayName();	 //在超類型的原型中定義的方法,對於子類型而言是沒法看到的
複製代碼

優勢

1.解決了1中,子類實例共享父類引用屬性的問題

2.建立子類實例時,能夠向父類傳遞參數

3.能夠實現多繼承(call多個父類對象)

缺點

1.實例並非父類的實例,只是子類的實例

2.只能繼承父類的實例屬性和方法,不能繼承父類原型屬性/方法

3.沒法實現函數複用,每一個子類都有父類實例函數的副本,影響性能

  • 組合函數

組合繼承(combination inheritance),有時候也叫作僞經典繼承,指的是將原型鏈和借用構造函數的 技術組合到一塊,從而發揮兩者之長的一種繼承模式。其背後的思路是使用原型鏈實現對原型屬性和方 法的繼承,而經過借用構造函數來實現對實例屬性的繼承。這樣,既經過在原型上定義方法實現了函數 複用,又可以保證每一個實例都有它本身的屬性

function Animal(name){
	this.name = name;
	this.colors = ["red","gray"];
}
function Dog(name){
	//繼承了Animal(屬性)
	Animal.call(this,name);
	this.color = "gray";
}
Animal.prototype.sayName = function(){
	alert(this.name);
}
//繼承方法
Dog.prototype = new Animal();
Dog.prototype.constructor = Animal;
 
var dog = new Dog("2");
dog.colors.push("hhh");
console.log(dog);
var animal = new Animal();
console.log(animal);
dog.sayName();	//能夠調用
複製代碼

優勢

1.能夠繼承實例屬性/方法,也能夠繼承原型屬性/方法

2.既是子類的實例,也是父類的實例

3.不存在引用屬性共享問題

4.經過call繼承父類的基本屬性和引用屬性並保留能傳參的優勢

5.函數可複用

缺點

1,子類原型上有一份多餘的父類實例屬性,由於父類構造函數被調用了兩次,生成了兩份,而子類實例上的那一份屏蔽了子類原型上的。

  • 原型式繼承

  • 寄生式繼承

  • 寄生組合式繼承

相關文章
相關標籤/搜索