最近都在巩固JS的基础知识,今天组要看的是有关继承方面的,每次看都会加深自己的理解呢

1.借助构造函数实现继承

原理:在子类中改变父类this的指向

 function Parent1() {
        this.name = 'parent1';
    }
    function Child1() {
        Parent1.call(this); //也可以使用 apply,改变函数运行的上下文;将父级的构造函数的this指向子类的实例
        this.type = 'child1';
    }
    console.log(new Child1());

在控制台打印的信息可以看出,Child1的实例继承了Parent1的name属性

缺点:不能继承父类原型对象上的方法或属性

在原有代码的基础上做如下修改:

 function Parent1() {
        this.name = 'parent1';
    }

    Parent1.prototype.say = function () {
        console.log('hi');
    };
    Parent1.prototype.color='red';

    function Child1() {
        Parent1.call(this); 
        this.type = 'child1';
    }  
      var s=new Child1();

在控制台进行查看,可以看到s并没有继承color属性和say()方法

2.借助原型链实现继承

function Parent2() {
        this.name = 'parent2';
    }

    function Child2() {
        this.type = 'child1';
    }  
/**
*原型链继承原理:s1是Child2的实例对象,它的__ptoro__属性指向Child2的原型对象,
*即Child2.prototype;代码中Child2.prototype=new Parent2(),等于Parent2的实例对
*象,因此可以继承Parent2
*/
Child2.prototype=new Parent2();    //重点
var s1 = new Child2();

缺点:原型链上的对象共享;如果父类Parent2中包含引用类型的属性,不同子类上的该属性是共享的,改变任意一个的值都会影响其他。

function Parent2() {
        this.name = 'parent2';
        this.play = [1, 2, 3];
    }

    function Child2() {
        this.type = 'child2';
    }

    Child2.prototype = new Parent2();   //重点

    var s1 = new Child2();
    var s2 = new Child2();
    console.log(s1.play, s2.play);
    s1.play.push(4);
    console.log(s1.play, s2.play);

虽然只改变了s1的play属性,但s2的也被改变了

3.组合继承方式;构造函数+原型链相结合

function Parent3() {
        this.name = 'parent3';
        this.play = [1, 2, 3];
    }

    function Child3() {
        Parent3.call(this);
        this.type = 'child3';
    }

    Child3.prototype = new Parent3();   

    var s3 = new Child3();
    var s4 = new Child3();
    s3.play.push(4);
    console.log(s3.play, s4.play);
//注意:s3.constructor是Parent3

组合方式虽然解决了共享的问题,即s3的play值得改变不会影响s4的play值;但是这种方式会使父级的构造函数执行两次,因此可以进行优化。

3-1.组合继承方式的优化1

function Parent4() {
        this.name = 'parent4';
        this.play = [1, 2, 3];
    }

    function Child4() {
        Parent4.call(this);
        this.type = 'child4';
    }
    Child4.prototype = Parent4.prototype;   

    var s5 = new Child4();
    var s6 = new Child4();
    s5.play.push(4);
    console.log(s5, s6);

不足:无法识别实例是由子类直接实例化还是由父类直接实例化的;s5的constructor是Parent4;因为Child4.prototype = Parent4.prototype;

 3.2 组合继承的完美写法

 

function Parent5() {
        this.name = 'parent5';
        this.play = [1, 2, 3];
    }

    function Child5() {
        Parent5.call(this);
        this.type = 'child5';
    }
//Object.create创建一个中间对象,原型对象是父类的原型对象
    Child5.prototype = Object.create(Parent5.prototype);   
    Child5.prototype.constructor = Child5

    var s7 = new Child5();
    var s8 = new Child5();
    console.log(s7, s8);