1、原型链继承:
共享父类(实例)属性方法
继承.jpg
function Child(){
this.subproperty=false
}
function Person(name){
this.property=true
this.name=name
this.child=[1,2,3,4]
}
Child.prototype=new Person("ming")//关键点
var x=new Child()
x.child.push(5)
console.log(x.child)//[1,2,3,4,5]
var y=new Child()
console.log(y.child)//[1,2,3,4,5]
关键代码:
Child.prototype=new Person("ming")//关键点
//执行Person构造函数,Person实例获得property,name,child属性,Child.prototype指向Person实例
Child:{
prototype:Person{//Person实例也是Child的原型
[[prototype]]:Person.prototype{//Person原型
constructor:Person
}
name:"ming",
property:true,
child:[1,2,3,4]
}
}
var x=new Child()
x.t="huan"
//new关键字 x. [[prototype]]=Child.prototype,导致继承Person,执行Child构造函数,添加自身属性subproperty
x:{
[[prototype]]:Person{
[[prototype]]:Person.prototype{
constructor:Person
},
name:"ming",//共享属性
property:true,//共享属性
child:[1,2,3,4]//共享属性
},
t:"huan",
subproperty:false
}
x.child.push(5)
//x实例访问并修改引用属性,原型搜索链:(1)x实例(无child属性)(2)Child.prototype(Person实例有Child属性,更改,实际也是在更改Person实例属性)停止搜索
var y=new Child()
//new关键字 y. [[prototype]]=Child.prototype,导致继承Person,执行Child构造函数,添加自身属性subproperty
y:{
[[prototype]]:Person{
[[prototype]]:Person.prototype{
constructor:Person
},
name:"ming",//共享属性
property:true,//共享属性
child:[1,2,3,4,5]//共享属性
},
subproperty:false
}
原型链继承:
优点:能够共享父类属性和方法,避免每个实例重新定义方法属性占内存
缺点:(1)共享属性如果是引用类型,容易被实例修改
(2)子类在创建实例时,不能动态的向父类构造函数传参,上述父类name值,在第一次使用Child.prototype=new Person("ming")时name值就固定了
2、借用构造函数继承:
(不使用Child.prototype=new Person("ming"),使用call为每个实力作用域复制其私有属性,非共享)
function Person(name){
this.property=true
this.name=name
this.child=[1,2,3,4]
}
function Child(name){
Person.call(this,name)
}
var x=new Child()
x.t="huan"
x.child.push(5)
console.log(x.Child)//[1,2,3,4,5]
var y=new Child()
console.log(y.Child)//[1,2,3,4]
Person.call(this,name)
//创建实例时执行代码,this指向实例对象,因此,这里的this其实是切换到Child实例作用域调用执行Person代码;
//call调用函数是在独立的特定作用域下执行的,每个实例调用后属性值互不干扰
因此,x.child.push(5)其实只作用于x作用域内
优点:能动态传值给父类构造函数,解决原型链的共享引用问题
缺点:相同的方法,不能共享,需要每个实例都声明解析,占内存
3、组合继承:
(原型链+借用构造函数):原型链定义公用方法和属性,借用构造函数定义实例独立方法和属性
个人理解:是因为每个实例在执行Person.call(this,name) 后屏蔽了Person实例中的相同属性,当实例中有了与原型同名的属性后,原型中的属性将会被屏蔽
function Person(name){
this.property=true
this.name=name
this.child=[1,2,3,4]
}
function Child(name){
Person.call(this,name)
}
Person.prototype.class=2
Person.prototype.getName=function(){
return this.name
}
Child.prototype=new Person()
var x=new Child("ming")
x.child.push(5)
console.log(x.child)//[1,2,3,4,5]
console.log(x.getName())//ming
var y=new Child("huan")
console.log(y.child)//[1,2,3,4]
解析:
Child.prototype=new Person()
Child:{
prototype:Person{//Person实例也是Child的原型
[[prototype]]:Person.prototype{//Person原型
constructor:Person
},
name:undefined,
property:true,
child:[1,2,3,4]
}
}
var x=new Child("ming")
//执行Child构造函数->执行Person.call()获得实例属性
x:{
[[prototype]]:Person{
[[prototype]]:Person.prototype{
constructor:Person
},
name:undefined,//共享属性
property:true,//共享属性
child:[1,2,3,4]//共享属性
},
name:"ming",//实例属性
property:true,//实例属性
child:[1,2,3,4]//实例属性
}
x.child.push(5)
//实例属性child变化,因为通过原型搜索链在实例中搜索到chid属性,搜索停止
x:{
[[prototype]]:Person{
[[prototype]]:Person.prototype{
constructor:Person
},
name:undefined,//共享属性
property:true,//共享属性
child:[1,2,3,4]//共享属性
},
name:"ming",//实例属性
property:true,//实例属性
child:[1,2,3,4,5]//实例属性
}
网友评论