Js是面对对象开发的编程语言
- 类:封装、继承、多态。
- 封装:类也是个函数,把实现的一个功能的代码进行封装,以此实现‘低耦合高内聚’。
- 多态:重载、重写
重写:子类重写父类上的方法(伴随着继承运行)
重载:相同的方法,由于参数或者返回值不同,具备了不同的功能(js不具备严格意义上的重载,同一个方法内,根据传参不同实现不同功能)
继承:子类的实例同时也具备父类中的私有属性和原型上的公共方法。
1、原型继承(让子类的原型=父类的实例,父类的 私有和公有属性都为子类公有)
原型继承的特点:
1、父类中私有和公有的属性方法,最后都会变为子类实例公有的。
2、和其他语言不同的是,原型继承并不会把父类的属性和方法拷贝给子类,而是让子类实例基于__proto__原型链查找到自己定义的属性和方法(查找方式)。
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); // Child {y: 200}
2、call继承(父类私有等于子类私有,只能继承父类中私有的,不能继承父类中公共的)
call继承的特点:
Call继承相当于把父类私有的拷贝为子类私有的,parent.call相当于普通函数执行,和父类原型就没关系了,因为没有创建父类实例,所以只能继承父类中的私有属性,无法实现继承父类的原型上公有属性。
function Parent(){
this.x = 100;
}
Parent.prototype.getX = function getX(){
return this.x;
}
function Child(){
// 在子类构造函数中,把父类当作普通方法执行(没有父类实例,也就不能调用父类原型上的属性和方法了)
Parent.call(this); // this = Child的实例c1
// this.x=100相当于强制给c1这个实例设置一个私有属性x=100,相当于让子类的实例继承了父类的私有属性,并且也成为子类私有的属性
this.y = 200;
}
Child.prototype.getY = function getY(){
return this.y;
}
let c1 = new Child;
console.log(c1); // Child {x: 100, y: 200}
3、寄生组合式继承(父类私有变为子类私有,父类公有变为子类公有)
寄生组合式继承特点:
先用parent.call继承,把父类私有的属性变为子类私有的属性,然后通过原型继承方式,改变原型链,把父类公有的,变为子类公有的属性。
function Parent(){
this.x = 100;
}
Parent.prototype.getX = function getX(){
return this.x;
}
function Child(){
Parent.call(this); // this = Child的实例c1
this.y = 200;
}
Child.prototype.__proto__ = Parent.prototype;
// 或者使用:Object.create,把父类原型挂载到子类原型上
// Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getY = function getY(){
return this.y;
}
let c1 = new Child;
console.log(c1); // Child {x: 100, y: 200}
4、ES6中的继承
class Parent{
constructor(){
this.x=100;
}
getX(){ // 相当于 Parent.prototype.getX=function……
return this.x;
}
}
// 继承: extends Parent(类似寄生组合继承)
class Child extends Parent{
constructor(){
super(); // 类似call继承,super(100,200)相当于把Parent中的constructor执行,传参100和200
this.y=200;
}
getY(){
return this.y;
}
}
let c1 = new Child();
console.log(c1); // Child {x: 100, y: 200}
super关键字:表示父类的构造函数,用来新建父类的this对象;
子类必须在constructor中调用super,否则新建实例会报错:
因为子类自己的this对象,需要通过父类的构造函数构造,从而得到父类实例的属性和方法,再加上子类实例的属性和方法。
这是基于ES6的继承机制,先将父类实例对象的属性和方法加到this上,再用子类的构造函数修改this。
class Son extends Person{
constructor(name){ // 写了constructor必须写super
super(name);//这里的super指向父类,即Person.call(this, name)
}
drink(){
super.drink(); //子类原型的方法中指向父类的原型
}
}