js继承的几种方式,以及缺点

1.原型链继承:可以继承属性和方法,但是会对原型上的方法误修改:

例如:继承属性

    //父类
    function Person(){
        this.head = 'aaa';
    }
    //子类
    function Student(s){
        this.s = s;
    }
    Student.prototype = new Person();
    var stu1 = new Student(1);
    console.log(stu1.head) //aaa
    stu1.head = 'bbb';
    console.log(stu1.head)//bbb
    var stu2 = new Student(1);
    console.log(stu2.head)//aaa

打印出bbb的地方,是因为stu1.head自己添加了一个本地属性,而并不会影响原型上的属性

例如:原型链继承方法:

//父类
function Person(){
    this.head = 'aaa';
    this.love = ['我','爱','你'];
}
//子类
function Student(s){
    this.s = s;
}
Student.protype = new Person();

var stu1 = new Student(1);
console.log(stu1.love);//我爱你

stu1.love.push('呀');
console.log(stu1.love);//我爱你呀

var stu2 = new Student(1);
console.log(stu2.love);//我爱你呀(这边并没有在本地修改,但是却对person里面的方法进行了修改)

2.借用构造函数继承
由于原型继承会对引用类型进行误修改,所以采用了构造函数继承方法,采用apply或call的形式

例如:

    function Person(){
        this.head = 'a';
        this.fn = ['a','b','c'];
    }
    function Student(s){
        this.s = s;
        Person.call(this);
    }
    var stu1 = new Student(1);
    console.log(stu1.fn);//'a','b','c'

    stu1.fn.push('eeeeee');
    console.log(stu1.fn);//'a','b','c','eeeeeee'

    var stu2 = new Student(1);
    console.log(stu2.fn); //'a','b','c','d'
Person.call(this),代表了把person构造函数借用给student函数,那么谁调用student,this就指向谁,因为创建了一个student实例,所以相当于Person.call(stu1),所以再修改就只是修改stu1这个实例对象,而不会影响其他

//缺点:这种形式的继承,每个子类实例都会拷贝一份父类构造函数的方法,作为实例自己的方法,占用

很多内存,而且当需求改变时,无法达到快速更新实例中的属性及方法

3.结合使用两种继承模式:

例如:

function Person(){
    this.eat = function(){
        this.head = 'aaa';
        this.a = ['a','b','c'];
    }
}
Person.prototype.eat = function(){
    console.log('aaa');
}
Person.prototype.sleep = function(){
    console.log('bbb');
}
function Student(id){
    this.id = id;
    Person.call(this);
}
Student.prototype = new Person();
Student.prototype.constructor = Student;

var stu1 = new Student(1);
console.log(stu1.a);//a,b,c

stu1.a.push('d');
console.log(stu1.a)//a,b,c,d

var stu2 = new Student(1);
console.log(stu2.a);//a,b,c

stu1.eat();//aaa
stu2.sleep();//bbb
console.log(stu1.constructor); //student

其实还有一个拷贝的方法,也可以模拟继承:

总结一下:
原型链继承:是通过子类的原型等于父类的实例对象,从而继承父类原型中的方法及属性.
缺点是:如果修改子类的实例对象中的方法,父类中原型的方法以及属性(引用类型)也会随着修改

借用继承:是父类call或apply借用给子类,子类的实例可以继承父类的属性和方法
缺点是:每一次新的实例对象继承,都要再一次继承父类中的所有属性及方法,很耗费内存空间

组合继承:采用了原型链继承+借用继承,保证了子类实例可以继承父类原型中的属性和方法,然后根据本地修改,而不需要每一次都继承父类,然后又用了借用,这样修改实例就不会影响父类的原型了

猜你喜欢

转载自blog.csdn.net/qq_39594951/article/details/81415688
今日推荐