js继承的几种方式

js继承的几种方式

    • 1、构造函数继承
    • 2、原型链继承
    • 3、组合继承
    • 4、组合继承优化1
    • 5、组合继承优化2
    • 6、组合继承优化3

1、构造函数继承

    function Parent1(name){
        this.name= name || 'Parent1';
    }
    Parent1.prototype.test=function(){}
    function Child1(name){
        Parent1.call(this,name);
        this.type='Child1';
    }
    console.log(new Child1('Parent1'),new Child1('Parent1').test);

js继承的几种方式_第1张图片
继承原理:在子类的函数体执行父类的构造函数,同时改变函数运行时的上下文(this指向),使this指向Child1,所以父类的属性都挂载到了子类上。
缺点:只是把父类的属性继承了,父类原型上的属性继承不了。

2、原型链继承

        function Parent2(){
        this.name='Parent2';
        this.arr1=[1,2,3];
    }
    Parent2.prototype.test=function(){}
    function Child2(){
        this.type='Child2';
    }
    Child2.prototype=new Parent2();
    Child2.prototype.constructor=Child2;
    var g1 = new Child2();
    var g2 = new Child2();
    console.log(g1.arr1,g2.arr1);
    g1.arr1.push(6);
    console.log(g1.arr1,g2.arr1);
    console.log(g1.__proto__.constructor);
    console.log(Parent2.prototype.constructor);

js继承的几种方式_第2张图片
原理:通过把Child2的prototype指向Parent2的实例
缺点:Child2实例修改原型上Parent2的私有属性,其他实例原型上Parent2的私有属性也会改变;创建子类实例时,无法向父类构造函数传参;子类实例和父类实例的原型对象上的成员有共享问题

3、组合继承

    // 组合继承
    function Parent3(name){
        this.name= name || 'Parent3';
        this.arr1=[1,2,3];
    }
    Parent3.prototype.test=function(){}
    function Child3(name){
        Parent3.call(this,name);
        this.type='Child3';
    }
    Child3.prototype=new Parent3();
    Child3.prototype.constructor = Child3;
    var g3 = new Child3();
    var g4 = new Child3();
    console.log(g3);
    console.log(g3.arr1,g4.arr1);
    g3.arr1.push(6);
    console.log(g3.arr1,g4.arr1);
    console.log(g3.__proto__.constructor);
    console.log(Parent3.prototype.constructor);

js继承的几种方式_第3张图片
原理:通过结合构造函数和原型继承两种优点,实现继承
缺点:原型的constructor指向不再指向子类;创建一个子类实例,父类构造函数执行了两次;子类实例和父类实例的原型对象上的成员有共享问题

4、组合继承优化1

    function Parent4(){
        this.name='Parent4';
        this.arr1=[1,2,3];
    }
    Parent4.prototype.test=function(){}
    function Child4(){
        Parent4.call(this);
        this.type='Child4';
    }
    Child4.prototype=Parent4.prototype;
    var g5 = new Child4();
    var g6 = new Child4();
    console.log(g5);
    console.log(g5.arr1,g6.arr1);
    g5.arr1.push(6);
    console.log(g5.arr1,g6.arr1);
    console.log(g5.__proto__.constructor);

js继承的几种方式_第4张图片
原理:通过把子类的prototype指向父类的prototype实现继承,避免父类构造函数执行了两次
缺点:原型的constructor指向不再指向子类;子类实例和父类实例的原型对象上的成员有共享问题

5、组合继承优化2

 function Parent5(){
            this.name='Parent5';
            this.arr1=[1,2,3];
        }
        Parent5.prototype.test=function(){}
        function Child5(){
            Parent5.call(this);
            this.type='Child5';
        }
        Child5.prototype=Object.create(Parent5.prototype);
        Child5.prototype.constructor=Child5;
        var g7 = new Child5();
        var g8 = new Child5();
        console.log(g7.__proto__.constructor);
        console.log(Parent5.prototype.constructor);

js继承的几种方式_第5张图片
子类实例和父类实例的原型对象上的成员有共享问题

6、组合继承优化3

        // 深度拷贝(将obj2的成员拷贝到obj1中, 只拷贝obj2自身属性)
        function deepCopy(obj1,obj2){
            for(var key in obj2){
                // 判断是否是obj2上的自身属性
                if(obj2.hasOwnProperty(key)){
                    // 判断是否引用类型的成员变量
                    if(typeof obj2[key] == 'object'){
                        obj1[key] = obj2[key].constructor == Array ? []:{};
                        deepCopy(obj1[key],obj2[key]);
                    }else {
                        obj1[key] = obj2[key];
                    }
                }
            }
        }

        // 组合继承优化3
        function Parent6(name){
            this.name=name || 'xiao';
            this.type='Parent6 type';
            this.arr1=[1,2,3];
        }
        Parent6.prototype.test=function(){}
        Parent6.prototype.arr2=[5,6]
        function Child6(name){
            Parent6.call(this,name);
        }
        // 使用深拷贝实现继承
        deepCopy(Child6.prototype,Parent6.prototype);
        var g9 = new Child6('天天');
        console.log(g9.__proto__.constructor);
        console.log(Parent6.prototype.constructor);

=>没有属性共享的问题,是以上最优的方案

你可能感兴趣的:(JS)