手记

再和“面向对象”谈恋爱 - super

在上一篇文章里介绍了继承,那其中说过一个很关键的东西想要继承子类里里必需先调用一个super方法。而super的作用绝对是价值连城!同时super的作用还有多种,并且跟你的使用环境有关系。

1、当作函数使用

super被当作函数使用,这种情况是最普遍的,上一篇文章里已经使用过。它有以下几种作用:

  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);

2、当作对象使用

super也可以被当作对象使用,被当作对象使用的时候情况有些复杂,跟上面是完全不一样的,同时又按使用环境分为了两种情况。

  1. 在普通方法中,指向父类的原型对象

  • 只能调用原型里的东西

  • 如果调用的是方法,那方法内部this指向子类实例

  • 如果用super去添加属性的话,super就是this(实例)

在私有方法中,指向父类,而不是父类的原型

  • 如果调用的是方法,那方法内部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';            //此处声明:请按注释标的序号顺序执行代码            //            /*             *  3、super设置属性             *      1、用super设置属性的话,super就代表当前环境的this。而当前环境为子类的constructor,所以此时的super代表的就是子类的实例对象             *      2、此时下面的showB()方法弹出的内容为"这是父类身上的共享方法,并且会弹出super就是this"是因为,如果super为this的话,那就与上面那段代码重复了,后面覆盖前面             *             */            super.b='super就是this';            /*             *  4、super获取属性             *      1、此时super的作用是获取属性,它依然指向父类的原型对象所以下面这句话相当于console.log(Father.prototype.b);所以结果为undefined。虽然在上面定义了super.b那也不会改变super的指向             */            console.log(super.b);     //undefined            /*             *  1、这里的super是一个对象,因为constructor是个普通对象             *      1、super指向父类的原型对象,调用的是Father的共享方法showB()             *      2、showB方法里的this指向子类的实例,取的是Father的constructor里定义的b             */            super.showB();  //这是父类身上的共享方法,并且会弹出子类实例的b            //2、super获取属性            console.log(super.a);   //父类原型的a   再次验证只能调用原型上的东西。原型上与constructor里都有个a,但是调的是原型上的        }    }    Son.b='子类的私有属性b';    new Son();}

在私有方法中使用

此时切记用super的用法与在普通方法中的用法完全相反

{    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';        }        /*         *  1、这里的super是在私有方法里调用,所以指向父类,调用的是Father里定义的static showB方法         *  2、此方法里的this指向被改成了子类,弹出的b是子类的私有属性b         */        static log(){            super.showB();        }    }    Son.b='子类的私有属性b';    Son.log();  //这是子类身上的私有方法,并且会弹出子类的私有属性b}

忠告:要明确指定supe的类型

super在用的时候必需指定它的类型,不然不清不楚的去用,浏览器会给你报错!

{    class Father{};    class Son extends Father{        constructor(){            super();    //这个是作为函数            //console.log(super);   //报错  那这个super它是个什么呢?它自己矛盾了,浏览器迷茫了~            console.log(super.a);   //这个是作为对象        }    }}

下一篇,实战!

0人推荐
随时随地看视频
慕课网APP