寄生式組合繼承可否優化?

問題:寄生式組合繼承可否優化?

一、修改子類原型對象的引用屬性,其父類的原型對象的引用屬性跟着改變
二、歡迎你們來指正!javascript

JavaScript中的多種繼承方式

1、混入式繼承:指的是字面量1繼承字面量2;

a) 實現方式:遍歷字面量2賦值給字面量1java

b) 注意點:必須用[]語法,不能用點語法app

c) 缺點:修改字面量1會對字面量2形成影響函數

 # 繼承的實現(混入式繼承)
    <script>
        var dog = {
                name: "啦啦小新",
                age: 20,
                friends: ["嘩啦嘩啦", "嗶哩嗶哩"]
            }
            //dog1
        var dog1 = {};
        //dog1 可以擁有dog對象中全部的屬性和方法
        //遍歷dog對象,拷貝它全部的屬性和方法設置到本身的身上
        for (var k in dog) {
            //使用[]語法
            dog1[k] = dog[k];
        }
        console.log(dog1);
        //問題:修改其中的某個對象dog1,會對原對象產生影響
        //爲何:引用類型的賦值(地址)
        dog1.friends.push("烏拉烏拉");
        嘩啦嘩啦", "嗶哩嗶哩","烏拉烏拉"]}
        console.log(dog); //{name: "啦啦小新",age: 20,friends: ["嘩啦嘩啦", "嗶哩嗶哩","烏拉烏拉"]}

    </script>

2、原型式繼承:經過設置其原型的方式繼承

a)實現方式:
i.設置構造函數的原型對象的屬性和方法(點語法),構造函數建立出來的對象自動共享原型對象中的屬性和方法
ii.設置構造函數的原型對象的屬性和方法(字面量法),構造函數建立出來的對象自動共享原型對象中的屬性和方法
iii.設置子對象的原型對象爲父對象的原型對象,再修正構造器,子對象構造函數建立出來的對象自動共享父對象的原型對象中的屬性和方法
b)注意點:使用原型替換的方式實現繼承的時候,原有原型對象中的屬性和方法會丟失
c)缺點:
i.修改一個對象的屬性和方法,會影響其餘的對象
ii.只能繼承原型屬性和方法,沒法繼承實例屬性和方法測試

  # 原型式繼承A
    <script>
        function Animal() {}
        //設置原型對象
        Animal.prototype.run = function() {
            console.log("run");
        }
        Animal.prototype.type = "貓科動物";
        //建立對象
        //性質:構造函數建立出來的全部對象都自動擁有其對於原型對象上面的全部屬性和方法
        var a = new Animal();
        console.log(a.type);
        a.run();
    </script>
    # 原型式繼承B
    <script>
        var obj = {
            name: "默認的名字",
            age: 20
        };

        function Animal() {}
        //設置原型對象
        Animal.prototype = obj;
        //修正構造器屬性
        Animal.prototype.constructor = Animal;
        //建立對象
        //性質:構造函數建立出來的全部對象都自動擁有其對於原型對象上面的全部屬性和方法
        var a = new Animal();
        console.log(a.name);
        console.log(a.age);
    </script>
    # 原型式繼承C
    <script>
        function Animal() {}
        //設置原型對象
        Animal.prototype.run = function() {
            console.log("run");
        }

        function Dog() {}
        //設置原型
        Dog.prototype = Animal.prototype;
        //建立對象
        var dog = new Dog();
        dog.run();
        //問題:
        //001 Dog 的原型對象和Animal的原型對象是同一個,不管是誰修改了原型對象會影響到另一個
        //002 只能繼承Animal的原型屬性和方法,沒法獲得其實例屬性和方法
    </script>

3、原型鏈繼承:是經過原型鏈的方式繼承

a)實現方式:
i.設置子對象的原型對象爲 new 父對象構造函數
ii.子對象構造函數建立出來的對象自動共享父對象中的屬性和方法(實例和原型屬性和方法);
b)注意點:
i.設置原型鏈繼承必須在設置子對象的屬性和方法以前
ii.若是設置同名的實例屬性或方法,會覆蓋父對象中的屬性和方法
iii.設置原型鏈繼承以後,須要修正構造器屬性指向
iv.完成繼承後再以字面量的方式設置子對象原型,會斷開繼承
c)缺點:
i.修改一個對象的屬性和方法,會影響其餘的對象
ii.沒法對父對象進行傳參優化

 # 構造函數A - B
    <script>
        //01 提供兩個構造函數
        //02 設置A構造函數的原型對象的屬性和方法
        //03 設置原型鏈繼承
        //04 建立B類型的對象 使用B構造函數來建立對象
        function A() {
            this.description = "描述信息";
            this.logDes = function() {
                console.log(this.description);
            }
        }
        A.prototype.name = "A的默認名稱";
        A.prototype.showName = function() {
            console.log(this.name);
        }

        function B() {};
        B.prototype = new A(); //完成繼承
             B.prototype.constructor = B; //修正構造器
        var b1 = new B();
        console.log(b1.name); //A的默認名稱
        b1.showName(); //A的默認名稱
        b1.logDes(); //描述信息
    </script>

4、借用構造函數繼承:是指經過借用別人的方法或屬性來實現繼承

a)實現方式:
i.子對象構造函數中設置:父對象構造函數.call/apply(this,參數);
ii.子對象構造函數建立出來的對象自動共享父對象中的實例屬性和方法(實例屬性和方法);
b)注意點:call和apply方法會改變this的指向,誰調用就指向誰
c)缺點:只能繼承實例屬性和方法,沒法繼承原型屬性和方法this

<script>
        //01 提供父類型的構造函數
        function SuperType(name) {
            //02 在構造函數中中設置實例屬性,該屬性爲引用類型
            this.family = ['哥哥', '姐姐', '爸爸', '媽媽'];
            //實例屬性
            this.name = name;
        };
        //03 提供子類型的構造函數
        function SubType() {
            //經典繼承|借用構造函數|僞造對象繼承
            //SuperType.call(this);
            //構造參數傳遞參數
            SuperType.call(this, '張老漢');
        };
        //04 建立父類型的實例對象,並對內部的實例化屬性進行修改
        var subDemo1 = new SubType();
        var subDemo2 = new SubType();
        console.log(subDemo1);
        alert(subDemo1.family); //哥哥,姐姐,爸爸,媽媽
        alert(subDemo2.family); //哥哥,姐姐,爸爸,媽媽
        subDemo1.family.push('爺爺', '奶奶');
        alert(subDemo1.family); //哥哥,姐姐,爸爸,媽媽,爺爺,奶奶
        alert(subDemo2.family); //哥哥,姐姐,爸爸,媽媽
        //測試構造函數傳遞參數
        alert(subDemo1.name);
    </script>

5、組合繼承:是指借用構造函數繼承和原型式繼承的組合

a)實現方式:
i.子對象構造函數中設置:父對象構造函數.call/apply(this,參數);
ii.設置子對象的原型對象爲父對象的原型對象;
iii.修正子對象的構造器;
iv.子對象構造函數建立出來的對象自動共享父對象中的屬性和方法(實例和原型屬性和方法);
b)注意點:call和apply方法是僞繼承 /沒有繼承關係 只是把Person構造函數的屬性和方法深複製一份(包括引用類型:指針和堆空間的數據)
c)缺點:修改子類原型方法和原型引用屬性,父類原型方法和原型引用屬性也跟着變prototype

 <script>
/*該繼承缺點:修改子類原型的方法,父類原型方法也跟着變,其*/
function Person(name) {
    this.name = name;
}
Person.prototype.age = 12;
Person.prototype.arr = [1,2,3];
Person.prototype.play = function() {
    console.log(this.name + "playfooterball");
}

function Student(name) {
    Person.call(this, name);
    /*僞繼承 沒有繼承關係 只是把Person構造函數的屬性和方法深複製一份(包括引用類型:指針和堆空間的數據)*/
}
Student.prototype = Person.prototype;
Student.constructor = Student;
Student.prototype.play = function() {
    console.log(this.name + "playbasketball");
}
var s1 = new Student("漳卅");
s1.arr.push(4);
console.log(s1); //Student對象
console.log(s1.age); //12
console.log(s1.arr);
s1.play(); // 漳卅playbasketball
var p = new Person("郭嘉");
p.play(); // 郭嘉playbasketball
console.log(p.arr);
</script>

6、寄生組合式繼承:優化了組合繼承中的修改子類原型方法,父類原型方法也跟着變的缺點

a)實現方法:
i.只需把組合繼承中的設置子對象的原型對象爲父對象的原型對象這一句;
ii.修改成子對象的原型對象爲object.create(父對象的原型對象);就OK了指針

<script>
function Person(name) {
    this.name = name;
}   
Person.prototype.age = 12;
Person.prototype.play = function () {
    console.log(this.name + "playfooterball");
}
Person.prototype.arr = [1,2,3];
function Student(name) {
     Person.call(this,name);
/*僞繼承 沒有繼承關係 只是把Person構造函數的屬性和方法深複製一份(包括引用  類型:指針和堆空間的數據)*/
}
Student.prototype = Object.create(Person.prototype);
Student.constructor = Student;
Student.prototype.play = function(){
    console.log(this.name + "playbasketball");
}
var s1 = new Student("漳卅");
s1.arr.push(4);
console.log(s1);//漳卅
console.log(s1.age);//12
Console.log(s1.arr);//[1,2,3,4]
s1.play();//漳卅 playbasketball
var p = new Person("郭嘉");
p.play();//郭嘉 playfooterball
console.log(p.arr);//[1,2,3,4]
</script>

上述代碼:修改子類的原型引用類屬性,其父類的原型引用類屬性跟着改變!code

相關文章
相關標籤/搜索