类继承的多种常用方案和原理

113 阅读2分钟

继承、封装、多态

  • 封装:把实现某个功能的代码进行封装处理,后期想实现这个功能,直接调用函数执行即可,"高内聚、低耦合"
  • 继承:子类继承父类的方法,子类的实例即拥有子类赋予的私有/公有属性方法,也想拥有父类赋予的私有/共有属性方法
  • 多态: 多态包括重载和重写
  1. 重载:后端语言中的重载,指的是「方法名相同,参数类型或个数不同,这样会认为是多个方法」
  2. 重写:子类重写父类中的方法

原型继承

特点:和传统后台语言中的继承不一样「后台:子类继承父类,会把父类的方法 cp 一份给子类」,并没有把父类的方法 cp 一份给子类,而是建立子类原型和父类之间的原型链指向,后期子类实例访问父类中提供的属性方法,也是基于 __proto__ 原型链一层层查找。

// 存在的问题:
//    @1 父类想要赋予其实例私有的属性 x,此时变成了子类实例 ys 的公有属性
//    @2 子类实例可以基于原型链,访问父类的原型对象,这很怪异 (ys.__proto__.prototype)
function Parent() {
	this.x = 100;
}

Parent.prototype.getX = function() {}


function Child() {
	this.y = 200;
}

Child.prototype = new Parent;
Child.prototype.getY = function() {}

let ys = new Child;

console.dir(ys);

call 继承

把父类当初普通方法执行「原型就没作用了」,让方法中的 this 是子类的实例,这样可以达到让父类中赋予其实例私有的属性,最后也变成子类实例的私有属性。

解决了原型继承的问题 1

// 存在的问题:
//    @1 子类实例可以基于原型链,访问父类的原型对象,这很怪异 (ys.__proto__.prototype)
function Parent() {
	this.x = 100;
}

Parent.prototype.getX = function() {}


function Child() {
	Parent.call(this);
	this.y = 200;
}

Child.prototype = new Parent;
Child.prototype.getY = function() {}

let ys = new Child;

console.dir(ys);

call + Object.create 组合式继承「推荐」

这样就只能通过 __proto__ 原型链来访问父类原型了。

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

Parent.prototype.getX = function() {}


function Child() {
	Parent.call(this);
	this.y = 200;
}

// 创建一个对象作为子类的原型链 对象的原型链指向 Parent.prototype
Child.prototype = Object.create(Parent.prototype);
Child.prototype.getY = function() {}

let ys = new Child;

console.dir(ys);

es6 extends 继承「非常类似于寄生组合继承」

class Parent {
	constructor() {
		this.x = 100
	}

	getX() {}
}

class Child extends Parent {
	constructor() {
		super();
		this.y = 200;
	}

	getY() {}
}

let ys = new Child;

console.dir(ys);