繼承的多種方式和優(yōu)缺點(diǎn)

原文出處

JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn)
JavaScript高級(jí)程序設(shè)計(jì)(第3版)

1.原型鏈繼承

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

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

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

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

        var instance = new SubType();
        console.log(instance.getSuperValue()); // true

SubType繼承了SuperType,是通過創(chuàng)建這個(gè)SuperType的實(shí)例,并將該實(shí)例賦值給SubType.property實(shí)現(xiàn)的,實(shí)現(xiàn)的本質(zhì)是重寫原型對(duì)象,代之以一個(gè)新類型的實(shí)例。

該例中的實(shí)例以及構(gòu)造函數(shù)和原型之間的關(guān)系如下圖:


原型鏈繼承的缺點(diǎn):

  1. 引用類型的屬性被所有實(shí)例共享,舉個(gè)例子:
        function SuperType() {
            this.colors = ["red", "blue", "green"];
        }
        function SubType() {
            
        }
        SubType.prototype = new SuperType();

        var instance1 = new SubType();

        var instance2 = new SubType();
        console.log(instance1.colors === instance2.colors);  //true
  1. 在創(chuàng)建 Child 的實(shí)例時(shí),不能向Parent傳參

實(shí)踐中很少會(huì)單獨(dú)使用原型鏈

2.借用構(gòu)造函數(shù)

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

        function SubType() {
            //繼承
            SuperType.call(this);
        }

        var instance1 = new SubType();
        var instance2 = new SubType();
        console.log(instance1.colors === instance2.colors); //false
        console.log(instance1 instanceof SubType);  //true
        console.log(instance1 instanceof SuperType);  //false

實(shí)現(xiàn)方式:通過在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)來實(shí)現(xiàn)繼承
優(yōu)點(diǎn):

  1. 避免了引用類型的屬性被所有實(shí)例共享
  2. 可以在 Child 中向 Parent 傳參
          function SuperType(name) {
            this.name = name;
        }

        function SubType() {
            //繼承了 SuperType,同時(shí)還傳遞了參數(shù) 
            SuperType.call(this, "Nicholas");
            //實(shí)例屬性 
            this.age = 29;
        }
        var instance = new SubType();
        console.log(instance.name); //"Nicholas";
        console.log(instance.age); //29

缺點(diǎn):方法都在構(gòu)造函數(shù)中定義,每次創(chuàng)建實(shí)例都會(huì)創(chuàng)建一遍方法。

        function SuperType(name) {
            this.name = name;
            this.sayName = function () {
                console.log(this.name);

            };
        }

        function SubType() {
            //繼承了 SuperType,同時(shí)還傳遞了參數(shù) 
            SuperType.call(this, "Nicholas");
            //實(shí)例屬性 
            this.age = 29;
        }
        var instance1 = new SubType();
        var instance2 = new SubType();
        console.log(instance1.sayName === instance2.sayName);  //false

3.組合繼承

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

        SuperType.prototype.sayName = function () {
            console.log(this.name);
        }
        function SubType(name, age) {
            //繼承屬性
            SuperType.call(this, name);
            this.age = age
        }
        //繼承方法
        SubType.prototype = new SuperType();
        SubType.prototype.constructor = SubType;
        SubType.prototype.sayAge = function() {
            console.log(this.age);
        };

        var instance1 = new SubType("Nicholas", 29);
        instance1.colors.push("black");
        console.log(instance1.colors);
        instance1.sayAge();
        instance1.sayName();
        
        var instance2 = new SubType("Greg", 27);
        console.log(instance2.colors);
        instance2.sayName();
        instance2.sayAge();

實(shí)現(xiàn)方式: 通過借用構(gòu)造函數(shù)模式來繼承屬性,通過原型鏈模式來繼承方法
優(yōu)點(diǎn):融合原型鏈繼承和構(gòu)造函數(shù)的優(yōu)點(diǎn),是 JavaScript 中最常用的繼承模式。

4.原型式繼承

        function object(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }        

        var person = {
            name: "Nicholas",
            friends: ["Shelby", "Court", "Van"]
        };

        var anotherPerson = object(person);
        var yetAnotherPerson = object(person)
        console.log(anotherPerson.friends === yetAnotherPerson.friends);

實(shí)現(xiàn)方式:即創(chuàng)建一個(gè)用于封裝繼承過程的函數(shù),在函數(shù)內(nèi)部將傳入的對(duì)象作為創(chuàng)建的對(duì)象的原型(就是 ES5 Object.create 的模擬實(shí)現(xiàn))。
缺點(diǎn):包含引用類型的屬性值始終都會(huì)共享相應(yīng)的值,這點(diǎn)跟原型鏈繼承一樣。

5.寄生式繼承

        function object(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }

        function createAnother(original) {
            var clone = object(original); //通過調(diào)用函數(shù)創(chuàng)建一個(gè)新獨(dú)享
            clone.sayHi = function () {  //以某種方式來增強(qiáng)這個(gè)對(duì)象
                console.log("hi");

            };
            return clone;  //返回這個(gè)對(duì)象
        }

        var person = {
            name: "Nicholas",
            friends: ["red", "Court", "van"]
        };

        var anotherPerson = createAnother(person);
        var yetanotherPerson = createAnother(person);
        console.log(anotherPerson.sayHi === yetanotherPerson.sayHi);  //false

優(yōu)點(diǎn):在原型式繼承的基礎(chǔ)上,增強(qiáng)了對(duì)象
缺點(diǎn):跟借用構(gòu)造函數(shù)模式一樣,每次創(chuàng)建對(duì)象都會(huì)創(chuàng)建一遍方法。

6.寄生組合式繼承

再來看下組合繼承的例子:

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

        function SubType(name, age) {
            SuperType.call(this, name); //第二次調(diào)用 SuperType()
            this.age = age;
        }
        SubType.prototype = new SuperType(); //第一次調(diào)用 SuperType()
        SubType.prototype.constructor = SubType;
        SubType.prototype.sayAge = function () {
            alert(this.age);
        };

組合繼承最大的缺點(diǎn)是會(huì)調(diào)用兩次父構(gòu)造函數(shù)。在第一次調(diào)用 SuperType 構(gòu)造函數(shù)時(shí),SubType.prototype 會(huì)得到兩個(gè)屬性: name 和 colors ;它們都是 SuperType 的實(shí)例屬性,只不過現(xiàn)在位于 SubType 的原型中。當(dāng)調(diào)用 SubType 構(gòu)造函數(shù)時(shí),又會(huì)調(diào)用一次 SuperType 構(gòu)造函數(shù),這一次又在新對(duì)象上創(chuàng)建了實(shí)例屬性 name 和 colors 。于是,這兩個(gè)屬性就屏蔽了原型中的兩個(gè)同名屬性。

使用寄生組合式繼承可以解決這個(gè)問題,如下:

        function object(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }

        function inheritPrototype(subType, superType) {
            var prototype = object(superType.prototype);  //創(chuàng)建對(duì)象
            prototype.constructor = subType;  //增強(qiáng)對(duì)象
            subType.prototype = prototype;  //指定對(duì)象
        }

        function SuperType(name) {
            this.name = name;
            this.colors = ["red", "blue", "green"];
        }
        SuperType.prototype.sayName = function() {
            console.log(this.name);
        };

        function SubType(name, age) {
            SuperType.call(this, name);
            this.age = age;
        }
        inheritPrototype(SubType, SuperType);  //解決組合繼承缺點(diǎn)
        SubType.prototype.sayAge = function() {
            console.log(this.age);
        };
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容