欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前端学习(六十) JavaScript-class继承(javaScript)

程序员文章站 2022-05-13 20:03:09
...

继承

在说继承之前,先看在E5及以前是怎么做继承的,下例是最常用的组合继承

        function Co4(name,age){
            this.name=name;
            this.age=age;
        }
        Co4.prototype={
            constructor:Co4,
            sayName:function(){
                console.log(this.name)
            }
        }
        function Co4N(name,age){
            Co4.call(this,name,age) //将对象指向Co4,如果没有,那么会默认指向Obejct
        }
        Co4N.prototype=new Co4();
        Co4N.prototype.constructor=Co4;
        Co4N.prototype.sayAge=function(){
            console.log(this.age);
        }
        let ah=new Co4N("ddd",123)
        ah.sayAge()

在ES6中的类里面,用到了关键字extends,先看示例

            class da{}
            class da1 extends da{}

那么上面ES5中的写法,改成类的写法,如下例

            class da{
                constructor(name,age){
                    this.name=name;
                    this.age=age
                }
                sayName(){
                    console.log(this.name);
                    }
                sayAge(){
                    console.log(this.age);
                    }
            }
            class da1 extends da{
                constructor(name,age){
                    super();    //一定要写表面调用父级方法
                    this.name=name;
                    this.age=age;
                }
                sayAge(){
                    super.sayAge()
                }
                sayName(){
                    super.sayName()
                }
            }
            let da2=new da1('aaarac',20);
            da2.sayAge()    //20
            da2.sayName()   //aaarac

这边有几个注意点,子类必须在constructor中调用super方法,就跟ES5中Co4.call(this,name,age),指明this是指向的Co4以及Co4N.prototype.constructor=Co4指明构造函数是Co4一样

至于为什么一定要在constructor中定义super()方法,实际上,当我们将子类实例化以后da1虽然是继承(extends)自da,但是并没有将父类的this一起继承过来,而本身又没有this,所以会报错,因此要用super来将父类的this一起拿过来,而且,super()在constructor中一定要置顶写,因为上面也说了,子类本身没有this的,所以如果this.name=name写在super()之前,那么会报一个错误,大致就是找不到this

那么静态方法呢,设置super()之后,会不会继承过来,上一篇没有设置super之前,子类是无法访问父类的static也就是静态方法的,答案是肯定的,如下示例

            class Es6dd{
                constructor(){}
                static sayName(){
                   console.log("hehesayName");
                   return "he2he2say2Name";
                }
            }         
            class Es6dd1 extends Es6dd{
                constructor(name){
                    super();
                    this.name=name;
                }
                sayName(){
                    console.log(this.name);
                    console.log(super.sayName());
                }
            }
            let _es6dd=new Es6dd1('hehehe');
            _es6dd.sayName();   

判断子类是否来源于某个父类

Object.getPrototypeOf()方法,这样就可以判断子类的归属

console.log(Object.getPrototypeOf(Es6dd1) === Es6dd);    //true

super

在class中,super是一个非常重要的关键字,作用是继承父类里的属性和方法,super一共有两种用法

  • 当方法使用super()
  • 当关键字使用,super.xxx

当作方法使用时,也就是super()必须放在constructor里,否则会报错,例如

            class Es6e{
                constructor(){}
                fuc(){
                    super();    //报错
                }
            }

当作关键字使用时不能直接使用,如下例

            class Es6e{
                constructor(){
                    super(); 
                    console.log(super); //报错,super后面需要跟上其他关键字方法,以用来调用父级类的属性方法
                    }
            }

然后super可以在其他方法里使用,作用是调用父级元素的属性方法

            class Es6dd{
                constructor(){}
                static sayName(){
                   return "he2he2say2Name";
                }
                sayAge(){
                   return "123";
                }
            }         
            class Es6dd1 extends Es6dd{
                constructor(name,age){
                    super();
                    this.name=name;
                    this.age=age
                }
                static sayName(){
                    console.log(super.sayName());
                    //console.log(super.sayName === Es6dd.prototype.sayName);
                }
                sayAge(){
                    console.log(super.sayAge());
                }
            }
            Es6dd1.sayName()
            let _es6dd=new Es6dd1('hehehe');
            _es6dd.sayAge();   

注意:静态方法只能被静态方法调用,非静态方法只能访问非静态方法,不能是非静态方法访问静态方法

如果进一步对比,会发现super调用是完全对等的,也可以这么说super === 父类.prototype

console.log(super.sayName === Es6dd.prototype.sayName);    //true

进一步了解super

            class n{
                constructor(){
                    this.age = 18
                }
            }
            class n1 extends n{
                constructor(){
                    super();
                    console.log(this.age);  //18
                    this.age=6;
                    console.log(this.age);  //6
                    super.age=12;
                    console.log(super.age,this.age);    //undefined,12
                    
                }
            }
            let n1a=new n1();

第一个打印:在设置super后,n1本身没有this.age属性,那么这时打印的是原型链上父类的this.age

第二个打印:这里给this.age赋值了6,那么打印的时候自然就获得了6

第三个打印:在打印之前,这里不是用this.age赋值了,用了super.age赋值,这时的super等同于this,规范就是这么规定的,但是打印结果的时候super.age变成了undefined,是因为,这里的调用,super.age等同于了n.prototype.age,但是n没有age属性,所以打印成了undefined,我是这么理解的,赋值操作的时候,super等同与this,调用的时候等同于prototype。

detele不能删除通过super的父类

            class m{
                constructor(){}
                age(){return 18}
            }
            class m1 extends m{
                constructor(){
                    super()
                }
                age(){
                    console.log(super.age());
                    
                }
                delage(){
                    delete super.age();    //无效果
                }
            }
            let m1a=new m1();
            m1a.delage();
            m1a.age()

另一种extends

重申一下,ES6的class只是一种语法糖本质上和ES5原型对象没有什么区别,只是为了语法更简单更简洁

就是之前说的ES6的新方法,setPrototypeOf()

setPrototypeOf(a,b)就是将b设置成a的原型对象等同

  • a extends b
  • let a =new b()