继承
- 是什么
- 继承是面向对象三大特性:继承、封装、多态 之一
- 具体来说就是让子类可以访问到父类的方法
- 实现方式有?
- 原型链继承
- 构造函数继承
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合式继承
- 类的继承
原型链继承
- 将父类的实例作为子类的原型来实现继承
- 缺点:多个实例对象共享一个原型对象
function Parent() {
this.name = 'parent';
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child() {
this.age = 18;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
const child1 = new Child();
const child2 = new Child();
console.log(child1.getName());
child1.colors.push('black');
console.log(child1.colors);
console.log(child2.colors);
构造函数继承
- 在子类构造函数中调用父类构造函数来实现属性继承
- 缺点:无法继承父类原型上的方法
function Parent() {
this.name = 'parent';
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child() {
Parent.call(this);
this.age = 18;
}
const child1 = new Child();
const child2 = new Child();
child1.colors.push('black');
console.log(child1.colors);
console.log(child2.colors);
console.log(child1.getName);
组合继承
- 利用原型继承和构造函数继承的特点,刚好可以解决他们的缺点
- 使用父类构造函数继承属性
- 设置子构造函数原型为父构造函数实例,继承原型
- 缺点:父类构造函数重复执行两次,导致实例对象和原型上都有属性,造成浪费
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.getName = function() {
return this.name;
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
const child1 = new Child('child1', 18);
const child2 = new Child('child2', 20);
child1.colors.push('black');
console.log(child1.colors);
console.log(child2.colors);
console.log(child1.getName());
console.log(child2.getName());
原型式继承
- 利用
object.create继承对象
- 缺点:多个实例对象共享一个原型对象
const parent = {
name: "parent",
colors: ["red", "blue", "green"],
getName: function () {
return this.name;
},
};
const child1 = Object.create(parent)
const child2 = Object.create(parent)
console.log(child1.getName(), child1.colors);
console.log(child2.getName(), child2.colors);
child1.name = "child1";
child1.colors.push("black");
child2.name = "child2";
console.log(child1.getName(), child1.colors);
console.log(child2.getName(), child2.colors);
寄生式继承
function createAnother(original) {
const clone = Object.create(original);
clone.sayHi = function() {
console.log('hi');
};
return clone;
}
const parent = {
name: 'parent',
colors: ['red', 'blue', 'green']
};
const child = createAnother(parent);
child.sayHi();
console.log(child.colors);
寄生组合式继承
- 结合了组合继承和寄生继承的优点
- 解决了继承的所有问题,是最优解
function Parent(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
Parent.prototype.getName = function () {
return this.name;
};
function Child(name, age) {
Parent.call(this, name);
this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child1 = new Child("child1", 18);
const child2 = new Child("child2", 20);
child1.colors.push("black");
console.log(child1.colors);
console.log(child2.colors);
console.log(child1.getName());
console.log(child2.getName());
类的继承
- ES6推出了class关键字,可以像一般面向对象语言一样使用class关键字定义对象,但本质上class是一种语法糖,底层还是使用原型实现的实例对象和继承
- 实现的效果和寄生组合式继承一样,实例属性不会相互影响
class Parent {
constructor() {
this.name = "parent";
this.colors = ["red", "blue", "green"];
}
getName() {
return this.name;
}
}
class Child extends Parent {
constructor(name) {
super();
this.name = name;
}
static sayHi() {
console.log("hi child");
}
}
const child1 = new Child('child1', 18);
const child2 = new Child('child2', 20);
child1.colors.push('black');
console.log(child1.colors);
console.log(child2.colors);
console.log(child1.getName());
console.log(child2.getName());