J49 JS的多种继承方式

183 阅读4分钟

1.JS本身是基于面向对象开发的编程语言

类:封装、继承、多态

  • 1.封装:类也是一个函数,把实现一个功能的代码进行封装,以此实现“低耦合高内聚”
  • 2.多态:重载、重写
    • 2.1 重写:子类重写父类上的方法(伴随着继承运行的)
    • 2.2 重载:相同的方法,由于参数或者返回值不同,具备了不同的功能(JS中不具备严格意义上的重载,JS中的重载:同一个方法内,根据传参不同实现不同的功能)
  • 3.继承:子类继承父类中的方法

2.重载

  • 1.后台语言执行顺序

    public void fn(int x,init y){
    
    }
    public void fn(int x){
    
    }
    //执行第一个FN
    fn(10,20); 
    
    // 执行第二个FN
    fn(10);
    
    //报错
    fn('张三');
    
  • 2.js语言不存在严格意义上的重载

    function fn(x, y) {
    
    }
    
    function fn(x) {
    
    }
    //执行第二个FN
    fn(10, 20); 
    
    //执行第二个FN 
    fn(10); 
    
  • 3.JS传参y===undefined,y不存在做什么事情

    function fn(x, y) {
    	if(y===undefined){
    		// ...y=0;
    		return;
    	}
    	// ....
    }
    //y===undefined,y不存在做什么事情
    fn(10);
    fn(10, 20); 
    

3.继承

  • 1.在JS语言中,它的继承和其它编程语言还是不太一样的
  • 2.继承的目的:让子类的实例同时也具备父类中私有的属性和公共的方法

1.JS中第一种继承方案:原型继承(让子类的原型等于父类的实例即可)

  • 1.子类的实例,能够用子类私有的和原型上公有的

  • 2.父类的实例,可以使用父类私有和原型上公有的

  • 原型继承的特点:

    • 1.父类中私有和共有的属性方法,最后都变为了类实例的共有的

    • 2.和其他语言不同的是原型继承并不会把父类的属性方法‘拷贝’给子类,而是让子类实例基于__proto__原型链找到自己定义的属性和方法指向/查找方式的

    • 3.C1__proto__.xxx=xxx修改子类原型(原有父类的一个实例)中的内容,内容被修改后,对子类的类其它实例有影响,但是对父类的实例不会有影响

    • 4.C1__proto__.proto.xxx=xxx直接修改的是父类原型,这样不仅会影响其它父类的实例,也影响写子类的实例

      function Parent() {
      this.x = 100;
      }
      Parent.prototype.getX = function getX() {
      return this.x;
      };
      
      function Child() {
      this.y = 200;
      }
      //让子类的实例同时也具备父类中私有的属性和公共的方法
      Child.prototype = new Parent; //=>原型继承
      Child.prototype.getY = function getY() {
      return this.y;
      };
      
      let c1 = new Child;
      console.log(c1); 
      

2.JS中第二种继承方式:CALL继承(只能继承父类中私有的,不能继承父类中公共的)

 //C1能用x和getX

function Parent() {
this.x = 100;
}
Parent.prototype.getX = function getX() {
return this.x;
};

function Child() {
// 在子类构造函数中,把父类当做普通方法执行(没有父类实例,
//父类原型上的那些东西也就和它没关系了)

// this -> Child的实例c1

// this.x=100 相当于强制给c1这个实例设置一个私有的属性x,
//属性值100,相当于让子类的实例继承了父类的私有的属性,
//并且也变为了子类私有的属性 “拷贝式”
Parent.call(this); 
this.y = 200;
}
Child.prototype.getY = function getY() {
return this.y;
};

let c1 = new Child;
console.log(c1); 

3.JS中第三种继承:寄生组合式继承(CALL继承 + 另类原型继承)

//C1能用x和getX

function Parent() {
	this.x = 100;
}
Parent.prototype.getX = function getX() {
	return this.x;
};

function Child() {

//1.改变this为parent
	Parent.call(this);

	this.y = 200;
}

//2.让子类的原型等于父类的原型
Child.prototype = Object.create(Parent.prototype);

// 3.破坏了原型,自己创建了原型,所有手动加coustructor保证原型的完整
Child.prototype.constructor = Child;

Child.prototype.getY = function getY() {
	return this.y;
};

let c1 = new Child;
console.log(c1); 

// 创建一个空对象,让其原型链指向obj
 let obj = {
	xxx: 'xxx'
};
console.log(Object.create(obj));   

4.ES6中的类和继承

//C1能用x和getX
class Parent {
constructor() {
	this.x = 100;
}
//1.类似原生 Parent.prototype.getX=function...
getX() {
	return this.x;
}
}

// 2.继承: extends Parent(类似于寄生组合继承)
// 3.注意:继承后一定要在CONSTRUCTOR第一行加上SUPER
class Child extends Parent {
constructor() {

//=>4.super();类似于我们之前的CALL继承 
//super(100,200):
//相当于把Parent中的constructor执行,传递了100和200
	super(); 
	this.y = 200;
}
getY() {
	return this.y;
}
}
let c1 = new Child;
console.log(c1);

// Child(); 
//=>Uncaught TypeError: Class constructor Child cannot be invoked without 'new' 
//ES6中创建的就是类,不能当做普通函数执行,只能new执行