1、原型链继承
缺点:原型链属性公用,若实例A修改,也会影响实例B
在创建 Child 的实例时,不能向 Parent 传参
function children(){
this.age = 17
}
function parent(){
this.name = 'dawan'
}
children.prototype = new parent();
const child = new children()
console.log(child.age);
console.log(child.name);
2、构造函数继承
缺点:继承实例属性时,实例对象的方法会占用多个空间,或者说,实例之间相同的方法被复制了一份, 而不是引用的同一个方法。 原因是我们用到构造函数,而方法都在构造函数中定义
,每次创建实例都会创建一遍方法, 造成内存浪费。
// 构造函数继承
// 父类
function Animal(name, age) {
this.name = name;
this.age = age;
this.colors = ['black', 'white'];
}
// 子类
function Dog(name, age, breed) {
Animal.call(this, name, age); // 核心:借用构造函数
this.breed = breed;
}
// 使用
const dog1 = new Dog('Buddy', 3, 'Golden');
const dog2 = new Dog('Max', 2, 'Bulldog');
console.log(dog1.name); // Buddy
console.log(dog1.breed); // Golden
// 验证引用类型不共享
dog1.colors.push('brown');
console.log(dog1.colors); // ['black', 'white', 'brown']
console.log(dog2.colors); // ['black', 'white']
3、组合继承(构造函数继承+原型链继承)
缺点:组合继承会调用两次构造函数
// 基本思想:书写构造函数继承,只不过把方法放在了原型上改进构造函数继承的弊端+调用了两次继承
// 组合继承
// 父类
function Animal(name) {
this.name = name;
this.colors = ['black', 'white'];
}
Animal.prototype.eat = function () { // -> 将方法放在原型上,解决了构造函数继承带来的会重复创建新的方法副本问题
console.log(this.name + ' is eating');
};
// 子类
function Dog(name, breed) {
Animal.call(this, name); // 第一次调用:继承实例属性 -> 在每个实例上创建了独立的属性,解决原型链继承带来的引用类型共享的问题
this.breed = breed;
}
Dog.prototype = new Animal(); // 第二次调用:继承原型方法
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function () {
console.log(this.name + ' is barking');
};
// 使用
const dog1 = new Dog('Buddy', 'Golden');
const dog2 = new Dog('Max', 'Bulldog');
dog1.eat(); // Buddy is eating
dog1.bark(); // Buddy is barking
4、寄生继承
// 寄生继承的核心是工厂函数模式,直接返回一个对象,所以不需要new
function createperson(name, age) {
let obj = {
name: name,
age: age,
sayhello: function () {
return `my name is${this.name}`
}
}
obj.newfn = function () {
return `my age is${this.age}`
}
return obj
}
const newperson = createperson('dawan', 19);
console.log(newperson.sayhello());
console.log(newperson.name)
console.log(newperson.age)
console.log(newperson.newfn())
5、寄生组合继承
ES6 class 的底层实现就是这个继承方法
核心处理:将组合继承中第二次继承封装为了一个函数,在这个函数里实际通过new的时候调用的是空对象,无副作用。优化了组合继承的弊端
// 寄生组合式继承
// 核心函数
function inheritPrototype(subType, superType) {
function F() { } // 空函数,调用时不执行任何代码
F.prototype = superType.prototype; // 只继承方法
subType.prototype = new F(); // 调用空函数,无副作用 组合继承的第二步调用就调用了这里
subType.prototype.constructor = subType;
}
// 父类
function Animal(name) {
this.name = name;
this.colors = ['black', 'white'];
}
Animal.prototype.eat = function () {
console.log(this.name + ' is eating');
};
// 子类
function Dog(name, breed) {
Animal.call(this, name); // 只调用一次
this.breed = breed;
}
// 把组合继承的直接调用写成了这样
inheritPrototype(Dog, Animal); // 寄生组合式继承
Dog.prototype.bark = function () {
console.log(this.name + ' is barking');
};
// 使用
const dog1 = new Dog('Buddy', 'Golden');
dog1.eat(); // Buddy is eating
dog1.bark(); // Buddy is barking