父类
function Animal (name = 'animal') {
//实例方法和属性
this.name = name;
this.age = '30';
this.printAge = function () {
return this.age
}
};
//原型方法
Animal.prototype.printName = function () {return this.name};
1.原型链继承
function Dog () {
//这里可以加实例方法和属性
};
Dog.prototype = new Animal();
//这里可以加子类的原型方法
let dog = new Dog();
let dog2 = new Dog();
dog2.obj.a = 'dog2'
console.log(dog.obj.a,dog2.obj.a) // dog2 dog2 来自原型对象的所有引用属性被所有实例共享
console.log(dog instanceof Animal) //true
console.log(dog instanceof Dog) //true
console.log(dog.name,dog.age) //animal 30
console.log(dog.printAge(),dog.printName()) // 30 animal
/**
* 优点:
* 1:非常纯粹的继承关系,实例是子类的实例,也是父类的实例;
* 2:父类新增原型方法/原型属性,子类都能访问到;
* 3:简单,易于实现;
* 缺点
* 1:可以在Cat构造函数中,为Cat实例增加实例属性。如果要新增原型属性和方法,则必须放在new Animal()这样的语句之后执行;
* 2:无法实现多继承;
* 3:来自原型对象的所有引用属性被所有实例共享;
* 4:创建子类实例时,无法向父类构造函数传参;
* */
2.盗用构造函数继承
function Dog() {
Animal.apply(this, arguments) //或者 Animal.call(this, ...arguments);
this.species = '金毛'
this.name = '大黄'
}
let dog = new Dog();
let dog2 = new Dog();
dog2.obj.a = 'dog2'
console.log(dog.obj.a,dog2.obj.a) //1 "dog2"
console.log(dog instanceof Animal) //false
console.log(dog instanceof Dog) //true
console.log(dog.name, dog.age, dog.species) //animal 30 金毛
console.log(dog.printAge(), dog.printName()) // 30 error:dog.PrintName is not a function 不能继承原型属性/方法
/**
* 优点:
* 1:解决了原型链继承中,子类实例共享父类引用属性的问题;
* 2:创建子类实例时,可以向父类传递参数
* 3:可以实现多继承(call多个父类对象)
*
* 缺点:
* 1:实例并不是父类的实例,只是子类的实例
* 2:只能继承父类的实例属性和方法,不能继承原型属性/方法
* 3:无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
* */
3.实例继承
function Dog (name = '大黄') {
let instance = new Animal();
instance.name = name;
return instance
}
let dog = new Dog('二狗');
console.log(dog)
console.log(dog instanceof Animal) //true
console.log(dog instanceof Dog) //false
console.log(dog.name, dog.age) //二狗 30
console.log(dog.printAge(), dog.printName()) // 30 二狗
/**
* 优点:
* 1:限制调用方式,不管是new 子类 还父类,返回的对象具有相同的效果;
*
* 缺点:
* 1:实例是父类的实例,不是子类的实例
* 2:不支持多继承
* */
4.拷贝继承
function Dog(name) {
const instance = new Animal();
for(const key in instance){
Dog.prototype[key] = instance[key]
}
this.name = name
}
let dog = new Dog('拷贝');
let dog2 = new Dog();
dog2.obj.a = 'dog2'
console.log(dog.obj.a, dog2.obj.a) //dog2 dog2
console.log(dog instanceof Animal) //false
console.log(dog instanceof Dog) //true
console.log(dog.name, dog.age) //拷贝 30
console.log(dog.printAge(), dog.printName()) // 30 拷贝
/**
* 优点:
* 1:支持多继承;
*
* 缺点:
* 1:效率较低,内存占用高(因为要拷贝父类的属性)
* 2:无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
* 3:来自原型对象的所有引用属性被所有实例共享;
* */
5.组合继承
function Dog () {
Animal.call(this,...arguments);
}
Dog.prototype = new Animal()
let dog = new Dog('组合继承');
let dog2 = new Dog();
dog2.obj.a = 'dog2'
console.log(dog.obj.a, dog2.obj.a) //1 "dog2"
console.log(dog instanceof Animal) //true
console.log(dog instanceof Dog) //true
console.log(dog.name, dog2.name,dog.age) //组合继承 animal 30
console.log(dog.printAge(), dog.printName()) // 30 组合继承
/**
* 优点:
* 1:弥补了构造继承的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法;
* 2:既是子类的实例,也是父类的实例;
* 3:不存在引用属性共享问题
* 4:可传参
* 5:函数可复用
*
* 缺点:
* 1:调用了两次父类构造函数,生成了两份实例;
*
* */
6.寄生组合继承
function Dog () {
Animal.call(this, ...arguments);
this.fn = () => 'nihaoa'
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog
let dog = new Dog('寄生组合继承');
let dog2 = new Dog();
dog2.obj.a = 'dog2'
console.log(dog.obj.a, dog2.obj.a) //1 "dog2"
console.log(dog instanceof Animal) //true
console.log(dog instanceof Dog) //true
console.log(dog.name, dog2.name,dog.age) //组合继承 animal 30
console.log(dog.printAge(), dog.printName(), dog.fn()) // 30 组合继承 nihaoa
/**
* 优点:
* 1:完美继承
*
* 缺点:
* 1:调实现较为复杂;
*
* */
参考文章:跳转链接