OOP 面向对象编程
Favori,
图:Nguyen Nhut
对象是什么?为什么要面向对象?
OOP(Object Oriented Programming)
逻辑迁移灵活,代码可复用性高,高度模块化
对象的理解
- 对象是对于单个物体的简单抽象
- 对象是一个容器,封装了属性&方法
属性: 对象的状态
方法: 对象的行为
// 简单对象
const Course = {
teacher: "john",
leader: "tom",
startCourse: function (name) {
return "oop";
},
};
// 函数对象
function Course() {
this.teacher = "john";
this.leader = "tom";
this.startCourse = function (name) {
return "oop";
};
}
构造函数
生成对象 需要一个模板,表征了一类物体的共同特征,从而生成对象 类即对象模板
js 本质不是基于类,而是基于构造函数+原型链 (constructor + prototype)
function Course() {
this.teacher = "john";
this.leader = "tom";
}
const course = new Course();
Course 本质就是构造函数
- 函数体内是用的 this, 代表所要生成的实例
- 生成对象通过 new 来实例化
- 可以做初始化参数
构造函数不初始化无法使用,如果需要使用,做如下兼容
function Course() {
const _isClass = this instanceof Course;
if (!isClass) {
return new Course();
}
this.teacher = "john";
this.leader = "tom";
}
new 是什么?
new 的原理?new 做了什么?手写 new?
function Course() {}
const course = new Course();
course.__proto__ === Course.prototype;
Course.prototype.__proto__ === Object.prototype;
course.constructor === Course;
- 创建了一个空对象,作为返回的对象实例
- 将生成空对象的原型对象指向了构造函数的 prototype 属性
- 将当前实例对象赋给了内部 this
- 执行构造函数初始化代码
constructor 是什么
function Course(teacher, leader) {
this.teacher = teacher;
this.leader = leader;
}
const course = new Course("john", "tom");
- 每个对象创建时会自动拥有一个构造函数属性 constructor
- constructor 继承自原型对象,指向构造函数的引用
使用构造函数的问题 构造函数中的方法,会存在于每个生成的实例中
原型对象
function Course() {}
const course1 = new Course();
const course2 = new Course();
-
构造函数:用来初始化对象的函数 - Course 自动给构造函数赋予一个属性 prototype,该属性实际等于实例对象的原型对象
-
实例对象:course1 就是实例对象,根据原型创建出来的实例 每个对象都有个proto 每个实例都有 constructor 属性 constructor 由继承而来,并指向当前构造函数
-
原型对象: Course.prototype
function Course() {
Course.prototype.teacher = "john";
const course1 = new Course();
const course2 = new Course();
}
继承
原型链继承
在原型对象的所有属性和方法,都能被实例所共享
- 子构造函数的原型是父构造函数的实例
- 子构造函数的原型的构造函数是子构造函数
function Game() {
this.name = "lol";
}
Game.prototype.getName = function () {
return this.name;
};
function LOL() {}
LOL.prototype = new Game();
LOL.prototype.constructor = LOL;
const game = new LOL();
构造函数继承
在子类构造函数内部调用父类构造函数
function Game() {
this.name = "lol";
this.skin = ["s"];
}
Game.prototype.getName = function () {
return this.name;
};
function LOL(arg) {
Game.call(this, arg);
}
const game3 = new LOL();
// 解决共享属性问题,传参问题
原型链上共享的方法无法被读取继承如何解决?
组合继承
function Game() {
this.name = "lol";
this.skin = ["s"];
}
Game.prototype.getName = function () {
return this.name;
};
function LOL(arg) {
Game.call(this, arg);
}
LOL.prototype = new Game();
LOL.prototype.constructor = LOL;
const game3 = new LOL();
无论何种场景都会调用两次父类构造函数,怎么办?
1、初始化子类
2、子类构造函数内部call父类的时候
寄生组合继承
function Game() {
this.name = "lol";
this.skin = ["s"];
}
Game.prototype.getName = function () {
return this.name;
};
function LOL(arg) {
Game.call(this, arg);
}
LOL.prototype = Object.create(Game.prototype);
LOL.prototype.constructor = LOL;
const game3 = new LOL();