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