再和「面向對象」談戀愛 - super(六)

上一篇文章裏介紹了繼承,那其中說過一個很關鍵的東西想要繼承子類裏裏必需先調用一個super方法。而super的做用絕對是價值連城!同時super的做用還有多種,而且跟你的使用環境有關係。javascript

一、看成函數使用

super被看成函數使用,這種狀況是最廣泛的,上一篇文章裏已經使用過。它有如下幾種做用:java

  1. super做爲函數調用時,表明父類的構造函數
  2. 調用super後,this會被改爲子類
  3. 只能用在構造函數裏,用在其它地方報錯
{
    class Father{
        constructor(){
            console.log(new.target.name);
        }
    }
    class Son extends Father{
        constructor(){
            super();
            this.a=10;  //這裏的this指向,Son的實例
        }
        method(){
            //super()    報錯,只能用在constructor裏
        }
    }
    new Father();    //Father(new.target返回Father類)
    new Son();        //Son(new.target返回Son子類)
    console.log(new Son().a);   //10 this指向被修改爲了子類的實例
}

子類裏面並無寫console.log,可是發現生成子類實例後,控制檯裏有輸出。說明:super其實至關於執行了父級的constructor方法。同時彈出的結果是指向了子類,又說明雖然調用的是父類的構造函數,可是調用完後會指向子類,this指向也被改爲了子類的實例。其實supe的做用至關於執行Father.prototype.constructor.call(this);segmentfault

二、看成對象使用

super也能夠被看成對象使用,被看成對象使用的時候狀況有些複雜,跟上面是徹底不同的,同時又按使用環境分爲了兩種狀況。瀏覽器

  1. 在普通方法中,指向父類的原型對象
* 只能調用原型裏的東西
* 若是調用的是方法,那方法內部this指向子類實例
* 若是用super去添加屬性的話,super就是this(實例)
  1. 在私有方法中,指向父類,而不是父類的原型
* 若是調用的是方法,那方法內部this指向子類而不是子類實例

在普通方法中使用

此時切記用super去獲取跟設置時的指向徹底不同函數

{
    class Father{
        constructor(){
            this.a='父類實例的a';
            this.b='父類實例的b';
        }
        showB(){
            console.log(`這是父類身上的共享方法,而且會彈出${this.b}`);
        }
        static showB(){    //私有方法能夠與上面的方法重名
            console.log(`這是父類身上的私有方法,而且會彈出${this.b}`);
        }
    }
    Father.prototype.a='父類原型的a';   //在原型身上的添加一個屬性a
    
    class Son extends Father{
        constructor(){
            super();    //這裏的super是個方法,做用爲引入父類的構造函數(看成函數使用)
            this.b='子類實例的b';
            
            //此處聲明:請按註釋標的序號順序執行代碼
            
            //
            /*
             *  三、super設置屬性
             *      一、用super設置屬性的話,super就表明當前環境的this。而當前環境爲子類的constructor,因此此時的super表明的就是子類的實例對象
             *      二、此時下面的showB()方法彈出的內容爲"這是父類身上的共享方法,而且會彈出super就是this"是由於,若是super爲this的話,那就與上面那段代碼重複了,後面覆蓋前面
             *
             */
            super.b='super就是this';
            
            
            /*
             *  四、super獲取屬性
             *      一、此時super的做用是獲取屬性,它依然指向父類的原型對象因此下面這句話至關於console.log(Father.prototype.b);因此結果爲undefined。雖然在上面定義了super.b那也不會改變super的指向
             */
            console.log(super.b);      //undefined
            
            
            /*
             *  一、這裏的super是一個對象,由於constructor是個普通對象
             *      一、super指向父類的原型對象,調用的是Father的共享方法showB()
             *      二、showB方法裏的this指向子類的實例,取的是Father的constructor裏定義的b
             */
            super.showB();    //這是父類身上的共享方法,而且會彈出子類實例的b
            
            
            //二、super獲取屬性
            console.log(super.a);   //父類原型的a   再次驗證只能調用原型上的東西。原型上與constructor裏都有個a,可是調的是原型上的
        }
    }
    Son.b='子類的私有屬性b';
    new Son();
}

在私有方法中使用

此時切記用super的用法與在普通方法中的用法徹底相反this

{
    class Father{
        constructor(){
            this.b='父類實例的b';
        }
        showB(){
            console.log(`這是父類身上的共享方法,而且會彈出${this.b}`);
        }
        static showB(){    //這是個私有方法,與上面的方法重名是能夠的
            console.log(`這是父類身上的私有方法,而且會彈出${this.b}`);
        }
    }
    Father.prototype.b='父類原型的b';   //在原型身上的添加一個屬性b
    
    class Son extends Father{
        constructor(){
            super();
            this.b='子類實例的b';
        }
        
        /*
         *  一、這裏的super是在私有方法裏調用,因此指向父類,調用的是Father裏定義的static showB方法
         *  二、此方法裏的this指向被改爲了子類,彈出的b是子類的私有屬性b
         */
        static log(){
            super.showB();
        }
    }
    Son.b='子類的私有屬性b';
    Son.log();    //這是子類身上的私有方法,而且會彈出子類的私有屬性b
}

忠告:要明確指定supe的類型

super在用的時候必需指定它的類型,否則不清不楚的去用,瀏覽器會給你報錯!prototype

{
    class Father{};
    class Son extends Father{
        constructor(){
            super();    //這個是做爲函數
            //console.log(super);    //報錯  那這個super它是個什麼呢?它本身矛盾了,瀏覽器迷茫了~
            console.log(super.a);   //這個是做爲對象
        }
    }
}

下一篇,實戰!code

相關文章
相關標籤/搜索