JavaScript繼承

原型鏈繼承

function SuperType() {
           this.property = true;
       }
        //  在原型鏈上定義方法。
       SuperType.prototype.getSuperValue = function (){
           return this.property;
       }

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

        //  替換SubType原型,達到繼承效果。
       SubType.prototype = new SuperType();

        //  開始寫SubType的方法,注:SubType的方法必須寫在替換SubType原型語句後
       SubType.prototype.getSubValue = function (){
           return this.subproperty;
       }

       var instance = new SubType();
       alert(instance.getSuperValue());

原型鏈繼承的原理如期名,是利用建立父類(SuperType)的實例,並將該實例賦值給子類(SubType).prototype實現的,實質是重寫子類的原型對象。app

原型鏈繼承特色:函數

  • 引用類型值的原型屬性會被全部實例共享。
  • 在建立子類型的實例時,沒辦法再不影響全部對象實例的狀況下向超類傳遞參數。
  • 即實現全部屬性方法共享,但沒法作到屬性、方法獨享

借用構造函數繼承

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

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

        var instance1 = new SubType();
        instance1.colors.push('black');
        alert(instance1.colors);  //red,blue,green,black
       
        var instance2 = new SubType();
        alert(instance2.colors);  //red,blue,green

借用構造函數繼承(constructor stealing),該繼承思想很簡單,即在子類型構造函數的內部調用超類型構造函數便可。經過call()方法(或apply()方法也能夠),實質上是在(將來將要)新建立的SubType實例的環境下調用SuperType構造函數。工具

借用構造函數繼承特色:this

  • 能夠在子類型構造函數中向超類型構造函數傳遞參數。
  • 方法都在構造函數中定義,沒法實現函數複用。
  • 超類型的原型中定義的方法對子類不可見。
  • 即實現全部屬性獨享,但沒法作到方法繼承

組合繼承

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);  //第二次調用SuperType
            this.age = age;
        }

        //繼承方法
        SubType.prototype = new SuperType();  //第一次調用SuperType
        SubType.prototype.constructor = SubType;
        SubType.prototype.sayAge = function(){
            alert(this.age);
        }

        var instance1 = new SubType('Y',21);
        instance1.colors.push('black');
        alert(instance1.colors);  //red,blue,green,black
        instance1.sayName();  //Y
        instance1.sayAge();  //21

        var instance2 = new SubType('Z',22);
        alert(instance2.colors);  //red,blue,green
        instance2.sayName();  //Z
        instance2.sayAge();  //22

組合繼承(combination inheritance)又叫僞經典繼承,是JavaScript中最經常使用的繼承模式。組合繼承指的是將原型鏈繼承和借用構造函數繼承的技術組合到一塊,從而發揮兩者之長的一種繼承模式。該模式經過借用構造函數繼承屬性,經過從新子類型prototype繼承方法。spa

組合繼承特色:prototype

  • 實現了全部方法共享,屬性獨享
  • instanceof()和isprototypeOf()可以識別基於組合繼承建立的對象。
  • 實現的時候調用了兩次超類(父類),產生多餘屬性。

原型式繼承

//  工具函數,實質是對傳入的對象執行一次淺拷貝。
        function object(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }

        var person = {
            name:'Y',
            friends:['S','C','V'],
            say:function () {
                alert(this.friends);
            }
        };

        var anotherPerson = object(person);
        anotherPerson.name = 'G';
        anotherPerson.friends.push('R');

        var yetAnotherPerson = object(person);
        yetAnotherPerson.name = 'L';
        yetAnotherPerson.friends.push('B');

        person.friends.push('my');

        anotherPerson.say();  //S,C,V,R,B,my
        alert(person.friends);  //S,C,V,R,B,my

原型式繼承是由道格拉斯·克羅克福德提出的,該模式要求你必須有一個對象能夠做爲另一個對象的基礎。該模式將一個對象傳遞給object()函數,而後再根據具體需求對獲得的對象加以修改便可。設計

原型式繼承特色:code

  • 以傳入object的對象爲原型,拷貝一個副本並反回。
  • 作不到函數複用,致使效率低。
  • 對象的引用類型全部實例共享(person的引用類型friends不只屬於person全部,並且也會被antherPerson和yetAnotherPerson共享)。

寄生式繼承

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

        function createAnother(original) {
            var clone = object(original);
            clone.sayHi = function (){
                alert(this.friends);
            };
            return clone;
        }
        var person = {
            name:'Y',
            friends:['S','C','V']
        };

        var anotherPerson = createAnother(person);
        anotherPerson.friends.push('test');
        anotherPerson.sayHi();

        var anotherPerson2 = createAnother(person);
        anotherPerson2.sayHi();

寄生式繼承(parasitic)一樣是由克羅克福德提出並推廣而之的。該模式建立一個僅用於封裝繼承過程的函數,該函數的內部以某種方式加強對象,最後再像真地式它作了全部工做同樣返回對象。對象

寄生式繼承特色:繼承

  • 作不到函數複用,致使效率低。
  • 對象的引用類型全部實例共享

寄生組合式繼承

function object(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }
        
        //  將超類型的prototype淺拷貝一遍並賦值給子類型的prototype
        //  (至關於利用超類型prototype重寫子類型prototype以達到繼承效果)
        function inheritPrototype(subType,superType) {
            var prototype = object(superType.prototype);
            prototype.constructor = subType;
            subType.prototype = prototype;
        }

        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);
            this.age = age;
        }

        //繼承方法
        inheritPrototype(SubType,SuperType);
        
        SubType.prototype.sayAge = function(){
            alert(this.age);
        }

        var instance1 = new SubType('Y',21);
        instance1.colors.push('black');
        alert(instance1.colors);  //red,blue,green,black
        instance1.sayName();  //Y
        instance1.sayAge();  //21

        var instance2 = new SubType('Z',22);
        alert(instance2.colors);  //red,blue,green
        instance2.sayName();  //Z
        instance2.sayAge();  //22

原理如圖:
圖片描述

寄生組合式繼承解決了組合繼承最大的問題——不管什麼狀況下,都會調用兩次超類型構造函數。該模式思路是:沒必要爲了指定子類型的原型而調用超類型的構造函數,咱們所需的無非就是超類型原型的副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,而後再將結果指定給子類型的原型。

寄生組合式繼承特色:

  • 實現了全部方法共享,屬性獨享
  • instanceof()和isprototypeOf()可以識別基於組合繼承建立的對象。

參考自《JavaScript高級程序設計》

相關文章
相關標籤/搜索