js继承的几种方式 1、构造函数继承2、原型链继承3、组合继承4、组合继承优化15、组合继承优化26、组合继承优化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);
继承原理:在子类的函数体执行父类的构造函数,同时改变函数运行时的上下文(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);
原理:通过把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);
原理:通过结合构造函数和原型继承两种优点,实现继承
缺点:原型的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);
原理:通过把子类的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);
子类实例和父类实例的原型对象上的成员有共享问题
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);
=>没有属性共享的问题,是以上最优的方案