原型链继承
function Parent(name,age){
this.name=name
this.age=age
}
Parent.prototype.sayName=function(){
console.log(this.name)
}
function Child(){}
Child.prototype=new Parent('xujii',21) //这句是原型链继承的重点
let c1=new Child()
c1.sayName() //查找路径: c1(没有)-->c1.__proto__(指向的是一个Parent实例,没有)-->c1.__proto__.__proto__(也就是Parent.prototype)最后才找到这个sqyName方法。
//执行该方法 ,输出c1.name(c1没有name,所以又查找,最后在c1.__ptoto__上面查找到),输出'xujii'
let c2=new Child()
c2.sayName() //和上面一样,输出'xujii'
从上述代码中可以看出原型链继承的缺点:子类实例会共享父类的属性和方法,不具有独立性。子类无法向父级传参数 优点:原型链完善
构造函数继承(经典继承)
function Parent(name,age){
this.name=name
this.age=age
}
Parent.prototype.sayName=function(){
console.log(this.name);
}
function Child(name,age){
Parent.call(this,name,age)
}
let c1=new Child('xujii',21)
let c2=new Child('tom',21)
console.log(c1.name); //输出xujii
console.log(c1.age); //输出21
// console.log(c1.sayName()); //报错
console.log(c2.name); //输出xujii
console.log(c2.age); //输出21
// console.log(c2.sayName()); //报错
从上述代码可以看出构造函数继承的优点:子实例不会共享父类的属性和方法,同时也可以向父类传参。缺点:子类只会继承父类本身的属性和方法,不会继承父类原型链上面的方法。原型链不完善
组合继承
组合继承是将原型链和构造函数继承结合。
function Parent(name, age) {
this.name = name
this.age = age
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
//原型链
Child.prototype=new Parent()
function Child(name, age) {
//构造函数
Parent.call(this, name, age)
}
let c1=new Child('xujii',21)
let c2=new Child('tom',21)
console.log(c1);
console.log(c2);
可以通过输出结果看出将原型链继承和构造函数继承组合,解决了共享的问题,同时原型链又是完善的。但是缺点在于:会调用两次构造函数
原型式继承
该继承用到了Object.create方法。
let obj=Object.create(obj2)
//方法规定参数obj2是obj的原型对象,所以obj.__proto__=obj2
模拟实现Object.create方法
function createObj(obj){
function F(){}
F.prototype=obj
return new F()
}
这个方法与原型链继承是相似的,不同之处在于:原型式继承不用去创建一个子类,直接创建一个子实例。
function Person(name){
this.name=name
}
let p1=new Person('xujii')
let c1=Object.create(p1)
//c1本身没有属性与方法,但是c1.__proto__=p1
let c2=Object.create(p1)
console.log(c1.name) //输出xujii
console.log(c2.name) //输出xujii
原型式继承的优点:如果只想创建一个与父类相似的对象,不想创建子类构造函数,该方法是可靠有效的。缺点:和原型链继承相同,会共享父类属性方法
寄生式继承
寄-->寄存在其他类的实例上面,拥有寄生对象的方法属性
生-->增加自己的方法属性
该继承方式是在原型式继承上面做了增强,不仅要继承要父类实例,还要写一些自己的方法属性
function Person(name){
this.name=name
}
let p1=new Person('xujii')
function create(obj){
let child=Object.create(obj) //创建这个实例对象(寄)
child.sayName=function(){ //增强这个实例对象(生)
console.log(this.name)
}
return child //返回这个实例对象
}
let c1=create(p1) //c1上面不仅有p1的属性和方法,也有完善的原型链,还有自己的方法sayName
寄生组合继承
寄生组合继承就是对组合继承的优化
function Parent(name, age) {
this.name = name
this.age = age
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
//组合继承
//Child.prototype=new Parent()
//优化
var F=function(){}
F.prototype=Parent.prototype
Child.prototype=new F()
//优化说明
//不直接让child连接到new Parent上面,而是通过间接使用一个函数来实现这个原型链的链接。这样就少了一次父类构造函数的调用。
function Child(name, age) {
Parent.call(this, name, age)
}
let c1=new Child('xujii',21)
let c2=new Child('tom',21)
console.log(c1);
console.log(c2);
优化一下
function Parent(name, age) {
this.name = name
this.age = age
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Child(name, age) {
Parent.call(this, name, age)
}
//新建方法--该方法可以实现少调用一次父类构造函数
function create(child,parent){
let obj=Object.create(parent.prototype)
obj.constructor=child
child.prototype=obj
}
//调用方法
create(Child,Parent)
引用《JavaScript高级程序设计》中对寄生组合式继承的夸赞就是:
这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Child.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变