es5 vs es6 继承

ES5 继承

借助构造函数继承(call, apply);无法继承父级原型上属性和方法

    function Animal(name, txt) {
        console.log('构造函数:Animal', this, name, txt)
        this.type = '父类'
        this.name = 'Animal_' + name;
        this.txt = txt
    }

    Animal.prototype.getName = function () {
        console.log('调用Animal原型上的方法:', this, this.name)
    };

    function Cat(name) {
        console.log('构造函数:Cat', this, name)
        this.name = 'Cat_' + name
        const txt = '构造函数继承,先创造子类的实例对象this(例如:cat1,cat2),调用call后, 构造函数Animal中的this指向Cat的实例对象'
        Animal.call(this, name, txt);
    }

    const cat1 = new Cat('1'); // new关键字将构造函数Cat中的this指向实例cat1
    console.log(cat1.type); // 继承animal的type属性
    // cat1.getName(); // 报错:无法继承原型上的方法和属性
    console.log(cat1.name); // Animal_1, 调用call后Animal中的this也指向cat1, 此时Cat构造函数中的name会被覆盖

原型继承;父级与子级无法动态传参,改变原型会导致所有实例都发生改变

     function Animal(name, txt) {
        console.log('构造函数:Animal', this, name, txt)
        this.type = '父类'
        this.name = 'Animal_' + name;
        this.txt = txt
    }

    Animal.prototype.getName = function () {
        console.log('调用Animal原型上的方法:', this, this.name)
    };

	 function Cat(name) {
       console.log('构造函数:Cat', this, name)
       this.name = 'Cat_' + name
       const txt = '构造函数继承,先创造子类的实例对象this(例如:cat1,cat2),调用call后, 构造函数Animal中的this指向Cat的实例对象'
       Animal.call(this, name, txt);
    }
    
    const animal = new Animal("1", '构造函数实例化'); // new关键字将构造函数Animal中的this指向实例animal
    animal.getName(); // 调用原型上的方法, Animal_1
 
    Cat.prototype = animal; // 原型继承, 无法动态传参
    const cat2 = new Cat('2'); // new关键字将构造函数Cat中的this指向实例cat2
    cat2.getName(); // cat没有 -> cat的原型__proto__ -> animal -> animal的原型__proto__

组合继承: 借助构造函数继承 + 原型链继承;两次调用父类的构造函数(耗内存)

    function Animal(name, txt) {
        console.log('构造函数:Animal', this, name, txt)
        this.type = '父类'
        this.name = 'Animal_' + name;
        this.txt = txt
    }

    Animal.prototype.getName = function () {
        console.log('调用Animal原型上的方法:', this, this.name)
    };

	 function Cat(name) {
       console.log('构造函数:Cat', this, name)
       this.name = 'Cat_' + name
    }
    
    const animal = new Animal("1", '构造函数实例化'); // new关键字将构造函数Animal中的this指向实例animal
    Cat.prototype = animal; // 原型链继承, 无法动态传参
    
    const cat2 = new Cat('2'); // new关键字将构造函数Cat中的this指向实例cat2
    cat2.getName(); // cat -> cat的原型__proto__ -> animal -> animal的原型__proto__
    console.log(cat2.name); // Animal_2, , 调用call后Animal中的this也指向cat2,此时Cat构造函数中的name会被覆盖function Animal

寄生组合继承; 可传参可原型继承

    function Animal(name, txt) {
        console.log('构造函数:Animal', this, name, txt)
        this.type = '父类'
        this.name = 'Animal_' + name;
        this.txt = txt
    }

    Animal.prototype.getName = function () {
        console.log('调用Animal原型上的方法:', this, this.name)
    };

	 function Cat(name) {
       console.log('构造函数:Cat', this, name)
       this.name = 'Cat_' + name
       const txt = '构造函数继承,先创造子类的实例对象this(例如:cat1,cat2),调用call后, 构造函数Animal中的this指向Cat的实例对象'
       Animal.call(this, name, txt);
    }
    
    Cat.prototype = Object.create(Animal.prototype); // 以父级的原型创建对象
    
    const cat2 = new Cat('2'); // new关键字将构造函数Cat中的this指向实例cat2
    cat2.getName(); // cat -> cat的原型__proto__ -> animal -> animal的原型__proto__
    console.log(cat2.name); // Animal_2, , 调用call后Animal中的this也指向cat2,此时Cat构造函数中的name会被覆盖function Animal

ES6 class 继承

为什么子类的构造函数,一定要调用 super()?

原因:ES6的继承机制与ES5完全不同。
ES5的继承机制,是先创造一个独立的子类的实例对象,然后再将父类的方法添加到这个对象上面,即“实例在前,继承在后”。
ES6 的继承机制,则是先将父类的属性和方法,加到一个空的对象上面, 然后再将该对象作为子类的实例,即“继承在前,实例在后”。
这就是为什么ES6的继承必须先调用super()方法,因为这一步会生成一个继承父类的this对象,没有这一步就无法继承父类。

核心概念

  • 私有的属性(#[prototyName])和方法(#[functionName])无能继承。
  • 如果子类没有定义 constructor()方法,这个方法会默认添加,并且里面会调用 super()。也就是说,不管有没有显式定义,任何一个子类都有 constructor 方法。’
  • 父类的静态属性和静态方法,也会被子类继承, 但是不能被实例继承。
  • 第一种情况,super 作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次 super 函数。第二种情况,super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
    class Person {
        constructor(name) {
            this.name = name;
        }
        static st_fn() {
            console.log('静态方法不能被实例继承,可被子类继承')
        }
        say() {
            console.log("say something:", this);
        }
    }

    class Child extends Person {
        constructor(name) {
            super(name) // 调用父类的构造函数constructor
        }
    }
    const person = new Person('父类');
    Child.st_fn();
    // person.st_fn(); // 静态方法不能继承,报错

你可能感兴趣的:(JavaScript,es6,javascript,前端)