(来自周哥课程知识点汇总,视频链接https://www.bilibili.com/video/BV1BK41177hb)
面向对象:封装,继承,多态
多态:重载、重写
JS不存在真正意义上的重载
JS中重载指的是同一个方法,根据传参不同,实现出不同的效果
*什么是面向对象?
面向对象是一种编程思想,JS本身就是基于面向对象构建出来的(例如: JS中有很多内置类,像Promise就是ES6中新增的一个内置类,我们可以基于new Promise来创建一个实例,来管理异步编程…)
JS中的面向对象,和其它编程语言还是有略微不同的,JS中类和实例是基于原型和原型链机制来处理的;而且JS中关于类的重载重写、继承也和其它语言不太一样…
继承:子类继承父类中的属性和方法(目的是让子类的实例能够调取父类中的属性和方法)
方案一:原型继承
让父类中的属性和方法在子类实例的原型链上
CHILD.prototype = new PARENT()
CHILD.prototype.constructor = CHILD
特点:
*1.不像其他语言中的继承一样(其它语言的继承一般是拷贝继承,也就是子类继承父类,
会把父类中的属性和方法拷贝一份到子类中,供子类的实例调取使用),
它是把父类的原型放到子类实例的原型链上,实例想调取这些方法,是基于_proto__原型链查找机制完成的
*2.子类可以重写父类上的方法(这样会导致父类其它的实例也受到影响)
*3.父类中私有或者公有的属性方法,最后都会变为子类中公有的属性和方法
方案二:CALL继承的特点:
*CHILD方法中把PARENT当做普通函数执行,让PARENT中的THIS指向CHILD的实例,
相当于给CHILD的实例设置了很多私有的属性或者方法
*1.只能继承父类私有的属性或者方法(因为是把PARENT当做普通函数执行,和其原型上的属性和方法没有关系)
*2.父类私有的变为子类私有的
方案三:寄生组合继承
CALL继承+类似于原型继承Object.create(PARENT.prototype)
特点:父类私有和公有的分别是子类实例的私有和公有属性方法(推荐)
方案四:class继承
class CHILD extends PARENT
/*继承:子类继承父类中的属性和方法(目的是让子类的实例能够调取父类中的属性和方法)
方案一:原型继承
让父类中的属性和方法在子类实例的原型链上
CHILD.prototype = new PARENT()
CHILD.prototype.constructor = CHILD
*特点:
*1.不像其他语言中的继承一样(其它语言的继承一般是拷贝继承,也就是子类继承父类,
会把父类中的属性和方法拷贝一份到子类中,供子类的实例调取使用),
它是把父类的原型放到子类实例的原型链上,实例想调取这些方法,是基于_proto__原型链查找机制完成的
*2.子类可以重写父类上的方法(这样会导致父类其它的实例也受到影响)
*3.父类中私有或者公有的属性方法,最后都会变为子类中公有的属性和方法
*/
function A(x) {
this.x = x;
}
A.prototype.getX = function () {
console.log(this.x);
}
function B(y) {
this.y = y;
}
B.prototype=new A(200); //将子类原型重定向
B.prototype.constructor=B; //保证原型重定向后的完整性
B.prototype.getY = function () {
console.log(this.y);
}
let b1 = new B(100) ;
b1.y;
b1.getY();
b1.getX(); //可以调用了getX()
原型链继承
/*
*CALL继承的特点:
* CHILD方法中把PARENT当做普通函数执行,让PARENT中的THIS指向CHILD的实例,
相当于给CHILD的实例设置了很多私有的属性或者方法
*1.只能继承父类私有的属性或者方法(因为是把PARENT当做普通函数执行,和其原型上的属性和方法没有关系)
*2.父类私有的变为子类私有的
*/
function A(x) {
this.x = x;
}
A.prototype.getX = function () {
console.log(this.x);
}
function B(y) {
//=>this: B的实例b1
A.call(this,200); //=>b1.x = 200 让PARENT中的THIS指向CHILD的实例
this.y = y;
}
B.prototype.getY = function () {
console.log(this.y);
}
let b1 = new B(100) ;
b1.y;
b1.getY();
b1.x; //B的实例b1拥有了父类私有的x属性
/*寄生组合继承:CALL继承+类似于原型继承Object.create(PARENT.prototype)
特点:父类私有和公有的分别是子类实例的私有和公有属性方法(推荐)
*/
function A(x) {
this.x = x;
}
A.prototype.getX = function () {
console.log(this.x);
}
function B(y) {
//=>this: B的实例b1
A.call(this,200); //=>b1.x = 200 让PARENT中的THIS指向CHILD的实例
this.y = y;
}
//=>object.create(OBJ):创建一个空对象,让空对象_proto_指向OBJ
B.prototype = Object.create(A.prototype); //Object.create(A.prototype)仅有公有属性方法
B.prototype.constructor = B;
B.prototype.getY = function () {
console.log(this.y);
}
let b1 = new B(100) ;
b1.y;
b1.getY();
b1.x; //B的实例b1拥有了父类私有的x属性
b1.getX(); //B的实例b1拥有了父类公有的方法
//b1有了自己私有的100,200,还有了父类的公有的方法
//手写Object.create来解决IE不兼容__proto__属性
/*Object.create = function (obj) {
function Fn() {}
Fn.prototype = obj;
return new Fn();
};
*/
寄生组合继承
//类
class A {
constructor(x){
this.x = x;
}
//加方法
getX() {
console.log(this.x);
}
}
//加属性方式
A.prototype.num=10;
//A()报错,不能当作普通函数执行,即call继承不能在次使用
class B extends A{
//子类只要继承父类,可以不写CONSTRUCTOR,一旦写了,
//则在CONSTRUCTOR中的第一句话必须是SUPER()
//不写CONSTRUCTOR,浏览器会自己默认创建
//CONSTRUCTOR(...args){ super(...args) }
constructor(y){
//A.call(this,200)
//Class constructor A cannot be invoked without 'new'
super(200);//super与constructor同在 =>A.call(this,200)
//super把父类当做普通方法执行,给方法传递参数,让方法中的THIS是子类的实例
this.y = y;
}
//加方法
getY() {
console.log(this.y);
}
}
//B.prototype = Object.create(A.prototype);
//不允许重定向原型的指向
let b1 = new B(100);
console.log(b1);