js中的继承

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)
  • 原型链图示:
    js中的继承

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)
上一篇:《QmlBook》笔记(5):锚


下一篇:1006_堆排序