1. 原型连继承
特点:让子类的原型指向父类的实例;
- 把父类的实例放到子类的原型链上,子类实例想要去调用这些属性和方法的时候,实际上是基于__proto__原型链查找的形式去完成的
- 子类实例可以直接修改父类上的方法(这样就会导致其他父类实例都会收到影响)
- 父类中私有的属性和方法,在实现原型链继承之后都会变成子类公有的属性和方法
//父类构造函数
function Parent(x){
this.x = x;
}
//父类原型
Parent.prototype.getX = function (){
console.log("getX",this.x)
}
//子类构造函数
function Child(y){
this.y = y;
}
Child.prototype = new Parent(100);
Child.prototype.constructor = Child;
Child.prototype.getY = function (){
console.log("getY",this.y)
}
//子类实例
let c1 = new Child(200);
console.log(c1)
- 原型链图示:
2. call 继承
特点:借用构造函数(call)继承
- 在Child方法中把父类构造函数当作普通的函数执行,让父类构造函数中的this指向Child的实例, 相当于给Child的实例设置了私有的属性和方法
- 只能继承父类的私有属性和方法(因为只是把Parent当作普通函数执行了一次,跟Parent的原型上的方法和属性没有任何关系)
- 父类私有的属性和方法都会变成子类私有的属性和方法
//父类构造函数
function Parent(x){
this.x = x;
this.sayHello = function (){
console.log("sayHello")
}
}
//父类原型
Parent.prototype.getX = function (){
console.log("getX",this.x)
}
//子类构造函数
function Child(y,x){
Parent.call(this,x);
// 等价于 Parent.call(this,x)
// this.x = x;
// this.sayHello = function (){
// console.log("sayHello")
// }
this.y = y;
}
Child.prototype.getY = function (){
console.log("getY",this.y)
}
//子类实例
let c1 = new Child(200,100);
3. 组合继承
特点:结合原型链继承和借用构造函数继承的方法
- 子类实例可以使用父类的私有属性和方法
- 父类私有的属性和方法也会变成子类实例私有的属性和方法
- 子类实例父类公有的属性和方法
- 子类的原型链上会存在一份多余的父类私有属性
//父类构造函数
function Parent(x){
this.x = x;
this.sayHello = function (){
console.log("sayHello")
}
}
//父类原型
Parent.prototype.getX = function (){
console.log("getX",this.x)
}
//子类构造函数
function Child(y,x){
Parent.call(this,666)
this.y = y;
}
Child.prototype = new Parent(100);
Child.prototype.constructor = Child;
Child.prototype.getY = function (){
console.log("getY",this.y)
}
//子类实例
let c1 = new Child(200,666);
4. 寄生组合继承
特点:结合原型链继承和借用构造函数继承的方法,同时需要自己创建prototype,实现寄生组合式继承
- 父类私有的属性和方法,子类实例私有的属性和方法
- 父类公有的属性和方法,子类实例公有的属性和方法
- 子类实例修改公有的属性和方法不会影响父类的实例
//父类构造函数
function Parent(x){
this.x = x;
this.sayHello = function (){
console.log("sayHello")
}
}
//父类原型
Parent.prototype.getX = function (){
console.log("getX",this.x)
}
let p1 = new Parent(100);
//子类构造函数
function Child(y,x){
Parent.call(this,666)
this.y = y;
}
// Child.prototype = new Parent(100);
// Child.prototype = {};
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getY = function (){
console.log("getY",this.y)
}
//子类实例
let c1 = new Child(200,666);
5. ES6 Class继承
特点:通过extends来实现的继承
- ES6继承 ==>class 子类构造函数 extends 父类构造函数{}
- 在ES6的class没有办法直接当作一个普通函数执行
- 必须使用new关键字来创建实例,不能当作一个普通函数执行
- 在使用ES6的继承的时候,没有办法直接重定向子类的原型
- Child.prototype.proto = Parent.prototype;
class Parent {
constructor(x) {
this.x = x;
this.sayHello = function () {
console.log("sayHello")
}
}
getX() {
console.log("getX==>", this.x)
}
}
class Child extends Parent {
//如果不写constructor,不会报错,继承会正常继承
//如果不写constructor浏览器会自动的帮我们去创建以下代码
// constructor(...args){
// super(...args)
// }
constructor(y) {
super(100);// Parent.call(this,100)
//Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
//如果是通过继承的形式写了constructor,那么就必须使用super来继承父类的私有属性和方法,不然就会报错
this.y = y;
}
getY(){
console.log("getY==>", this.y)
}
}
let c1 = new Child(200)