n">;let child1=newChild()
console.log(child1)
console.log(child1.name)
上面代码看似没问题,实际存在潜在问题
let child1=newChild();let child2=newChild();
child1.play.push(4);
console.log(child1.play);
console.log(child2.play);
改变child1的play属性,会发现child1也跟着发生变化了,这是因为两个实例使用的是同一个原型对象,内存空间是共享的
优点:不仅能继承父类的实例属性和方法,还能继承原型属性或者方法
缺点:父类的引用属性被共享了,改动一处其他的也会被改
构造函数继承
借助call调用Parent函数
functionParent2(){this.name='parent1';this.age='18';}Parent2.prototype.getName=function(){returnthis.name;}functionChild(){Parent2.call(this);this.type='child'}let child=newChild();
console.log(child);
console.log(child.getName());
可以看到,父类原型对象中一旦存在父类之前自己定义的方法,那么子类将无法继承这些方法
相比第一种原型链继承方式:
优点:父类的引用属性不会被共享,优化了第一种继承方式的弊端
缺点:但是只能继承父类的实例属性和方法,不能继承原型属性或者方法
组合继承
前面我们讲到两种继承方式,各有优缺点。组合继承则将前两种方式继承起来
functionParent3(){this.name='parent3';this.play=[1,2,3];}Parent3.prototype.getName=function(){returnthis.name;}functionChild3(){Parent3.call(this);this.type='child3';}Child3.prototype=newParent3();Child3.prototype.constructor= Child3;var s3=newChild3();var s4=newChild3();
s3.play.push(4);
console.log(s3.play, s4.play);
console.log(s3.getName());
console.log(s4.getName());
这种方式看起来就没什么问题,方式一和方式二的问题都解决了,但是从上面代码我们也可以看到Parent3 执行了两次,造成了多构造一次的性能开销
原型式继承
这里主要借助Object.create方法实现普通对象的继承
同样举个例子
let parent4={
name:"parent4",
friends:["p1","p2","p3"],getName:function(){returnthis.name;}};let person4= Object.create(parent4)
person4.name='tom'
person4.friends.push('jerry ')let person5= Object.create(parent4)
person5.friends.push('lucky')
console.log(person4.name);
console.log(person4.name=== person4.getName());
console.log(person5.name);
console.log(person4.friends);
console.log(person5.friends);
这种继承方式的缺点也很明显,因为Object.create方法实现的是浅拷贝,多个实例的引用类型属性指向相同的内存,存在篡改的可能
寄生式继承
寄生式继承在上面继承基础上进行优化,利用这个浅拷贝的能力再进行增强,添加一些方法
let parent5={
name:"parent5",
friends:["p1","p2","p3"],getName:function(){returnthis.name;}};functionclone(original){let clone= Object.create(original);
clone.getFriends=function(){returnthis.friends;};return clone;}let person5=clone(parent5);
console.log(person5.getName());
console.log(person5.getFriends());
其优缺点也很明显,跟上面讲的原型式继承一样
寄生组合式继承
寄生组合式继承,借助解决普通对象的继承问题的Object.create 方法,在前面几种继承方式的优缺点基础上进行改造,这也是所有继承方式里面相对最优的继承方式
functionclone(parent, child){
child.prototype= Object.create(parent.prototype);
child.prototype.constructor= child;}functionParent6(){this.name='parent6';this.play=[1,2,3];}Parent6.prototype.getName=function(){returnthis.name;}functionChild6(){Parent6.call(this);this.friends='child5';}clone(Parent6, Child6);Child6.prototype.getFriends=function(){returnthis.friends;}let person6=newChild6();
console.log(person6);
console.log(person6.getName());
console.log(person6.getFriends());
可以看到 person6 打印出来的结果,属性都得到了继承,方法也没问题
文章一开头,我们是使用ES6 中的extends关键字直接实现JavaScript的继承
classPerson{constructor(name){this.name= name}getName=function(){
console.log('Person:',this.name)}}classGamerextendsPerson{constructor(name, age){