前端必备:深入剖析原型链继承,轻松掌握JavaScript核心机制!

55 阅读2分钟

function Parent(){ //构造函数
  this.name=['奶茶不加冰七分甜']
}
Parent.prototype.getName=function(){
  return this.name
}
const newparent=new Parent() //实例
console.log(newparent.__proto__===Parent.prototype) //true,实例中的__proto__等于构造函数中的原型prototype

console.log(Parent.prototype.constructor===Parent) //true //原型对象Parent.prototype中的constructor等于构造函数Parent

1.原型链继承

有弊端:修改了其中一处子类实例的原型会影响其他子类实例的原型也跟着改变。因为她们指针指向同一个原型


function Parent(){ //构造函数
  this.name=['张三']
}
Parent.prototype.getName=function(){
  return this.name
}

function Child(){ //构造函数
  
}

//原型链继承(有弊端)
//Child的原型指向Parent的实例。弊端:修改了其中一处Child实例的原型会影响其他Child实例的原型也跟着改变。因为她们指针指向同一个原型
Child.prototype=new Parent() 
let child1=new Child()
let child2=new Child()
console.log(child1.__proto__===Child.prototype)//true
console.log(child2.__proto__===Child.prototype) //true
console.log(child1.__proto__===child2.__proto__) //true
child1.name[0]='李四' //更改了原型Child.prototype中的name
console.log(child2.name[0]) //"李四"
console.log(Child.prototype.name[0]) //"李四"

2.构造函数继承

有弊端:子类没有继承父类原型

function Parent(name){ //构造函数
  this.age=19
  this.name=[name]
}
Parent.prototype.getName=function(){
  return this.name
}

function Child(){ //构造函数
  Parent.call(this,'张三') //构造函数继承,优点:每个Child实例化都是独立的作用域,弊端:父类原型没有继承
}
let child1=new Child()
let child2=new Child()

child1.name[0]='李四'
console.log(child2.name[0])//张三
console.log(child1.getName) //调用getName方法报undefined

3.组合式函数继承(把原型链继承和构造函数继承结合起来)

有弊端:子类的原型继承了整个父类的实例,导致重复继承,比如Child实例已经继承了父类的name和age属性,但是Child.__proto__原型中也有name和age属性,导致不必要的属性和方法重复继承

function Parent(name){ //构造函数
  this.age=19
  this.name=[name]
}
Parent.prototype.getName=function(){
  return this.name
}

function Child(){ //构造函数
  Parent.call(this,'张三') ///构造函数继承,call改变this指向,this指向Child实例
}
Child.prototype=new Parent() //子类的原型继承了整个父类的实例

let child1=new Child() //Child实例
let child2=new Child() //Child实例

child1.name[0]='李四'

console.log(child2.name[0])//张三
console.log(child1.getName()) //"[李四]"

4.寄生组合式函数继承(在组合式函数继承基础上进行改良)

function Parent(name){ //构造函数
  this.age=19
  this.name=[name]
}
Parent.prototype.getName=function(){
  return this.name
}

function Child(){ //构造函数
  Parent.call(this,'张三') ///构造函数继承,call改变this指向,this指向Child实例
}

//Child.prototype=Parent.prototype 这样写是不对的,会导致给子类的原型添加方法,父类也会添加该方法,因他们指针指向同一个堆内存。应该用浅拷贝拷贝父类的原型方法,新建一个新的指针。
Child.prototype=Object.create(Parent.prototype) //改良部分

Child.prototype.editName=function(newname){
  this.name[0]=newname
}
let child1=new Child()
let child2=new Child()

child1.name[0]='李四'

child2.editName('王小二')
console.log(child2.name[0])//'王小二'