一.面向对象
(1)对象是什么?为什么要面向对象?
通过对代码的抽象,进而描述单个种类物体的方式.
(2)特点:面向对象-逻辑上迁移更加灵活,代码的复用性更高,高度的模块化.
(3)对象的理解
1.对象是对于单个物体的简单抽象;
2.对象是容器,封装了属性和方法
**属性:对象状态
**方法:对象的能力/行为
//简单对象
const Course = {
teacher: 'tom',
leader: 'xh',
startCourse: name => {
return `开始${name}课`
}
}
//A同学
Course.teacher = 'xxx'
Course.startCourse('react')
//B同学
Course.startCourse('vue') //发现即使课变了,但是老师也被修改了
//引出函数对象
function Course(){
this.teacher='tom'
this.leader='xh'
this.startCourse= name => {
return `开始${name}课`
}
}
##构造函数
####需要一个模板-表征了一类物体的共同属性,从而生成对象.
####类即对象模板
#### js本质并不是基于类,而是基于构造函数+原型链
### Course本质就是构造函数
*1.函数体内使用的this,指向所要生成的实例;
2.生成对象用new来实例化;
3.可以初始化传参.
function Course() {
this.teacher = 'tom' //这里的this其实指向course 这个实例对象
this.leader = 'xh'
this.startCourse = name => {
return `开始${name}课`
}
}
const course = new Course(args)
####追问:如果构造函数不初始化,可以使用具有相同能力吗?->无法具有
####如果在项目中需要使用,且不希望外界进行感知情况下,如何让外界直接拿到实例化后的对象?=>单例模式
function Course() {
const _isClass = this instanceof Course
//未实例化
if (!_isClass) {
return new Course
}
this.teacher = 'tom'
this.leader = 'xh'
this.startCourse = name => {
return `开始${name}课`
}
}
//使用方
const course=Course()
启发:编写底层api代码时,尽量做到不让外界去感知区分内部类型.
####引发思考:new是什么?/new的原理是什么?/new的时候做了什么?
function Course() { }
const course = new Course()
*总结:1.结构上:创建了一个空对象,作为返回的对象实例;
2.属性上:将生成空对象的原型对象指向了构造函数的prototype属性;
3.关系上:将当前实例对象赋值给了内部的this;
4.生命周期上:执行了构造函数的初始化代码.
####追问:实例属性影响-独立的
function Course(teacher, leader) {
this.teacher = teacher
this.leader = leader
}
const course1 = new Course('tom', 'xh')//course1.teacher ->tom
const course2= new Course('steven', 'bubu')//course2.teacher ->steven
course2.teacher='xxx'//course.teacher=>tom
//分析过程:course1 是构造函数的实例化对象,而this指向了这个实例化对象,所以this.teacher和this.leader
//是实例化对象上的属性,而构造函数new Course时,调用了Course()这个函数传入的参数,所以实例化对象的teacher
//属性也就指向了调用Course()这个函数传入的参数.
###拔高:用js手写一个new
function usernew(obj, ...args) {
const newObj = Object.create(obj.prototype)
const result = obj.apply(newObj, args)
return typeof result === 'object' ? result : newObj
}
###constructor是什么?
function Course(teacher, leader) {
this.teacher = teacher
this.leader = leader
}
const course1 = new Course('tom', 'xh')//course1.teacher ->tom
*1.每个对象创建时,会自动拥有一个构造函数属性constructor;
2.constructor源自原型对象,指向了构造函数的引用.
*实例获得了模板的属性=>(大胆点)继承了类的属性
####原型对象
function Course(){}
const course1 = new Course()
const course2 = new Course()
//1.Course - 用来初始化创建对象的函数 | 类
course1.__proto__===Course.prototype
//2.course1 - 根据原型创建出来的实例
course1.constructor===Course
*prototype是什么?
function Course() {
this.teacher = 'tom'
this.leader = 'xh'
}
Course.prototype.startCourse = name => {
return `开始${name}课`
}
const course1 = new Course()
*追问:原型对象有自己的原型链吗?
course1.__proto__.__proto__ === Object.prototype
Course.prototype.__proto__ === Object.prototype
course1.__proto__.__proto__.__proto__ === null
原型链
完整的原型图:
**继承
js如何实现继承?
####在原型对象的所有属性方法,都可以被实例所共享
function Game() {
this.name = 'lol'
}
Game.prototype.getName = function () {
return this.name
}
//LOL
function LOL() { }
LOL.prototype = new Game()//将LOL的原型对象指向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() { }
LOL.prototype = new Game()//将LOL的原型对象指向Game的实例
LOL.prototype.constructor = LOL
const game1 = new LOL()
const game2 = new LOL()//game2也会拿到新添加的属性值
game1.skin.push('ss')
*1.父类属性一旦赋值给子类的原型属性,此时属性属于子类得共享属性了;
*2.实例化子类时,元素无法向父类进行传参.
###解决方法:构造函数继承
####经典继承:在子类得构造函数内部使用父类的构造函数
function Game(args) {
this.name = 'lol'
this.skin = ['s']
}
Game.prototype.getName = function () {
return this.name
}
function LOL(args) {
Game.apply(this, args)//调用Game的this,并传递参数
}
const game3 = new LOL('args')
解决了共享属性问题+子向父传参的问题.
###追问::原型链上的共享方法无法被读取继承,如何解决?
####组合继承
function Game(args) {
this.name = 'lol'
this.skin = ['s']
}
Game.prototype.getName = function () {
return this.name
}
function LOL(args) {
Game.apply(this, args)//调用Game的this,并传递参数
}
LOL.prototype = new Game()//调用
LOL.prototype.constructor = LOL
const game4 = new LOL('args')//调用
###追问:组合继承缺点?问题在于,无论何种场景,都会调用两次父类的构造函数.
###解决方案:寄生组合继承
function Game(args) {
this.name = 'lol'
this.skin = ['s']
}
Game.prototype.getName = function () {
return this.name
}
function LOL(args) {
Game.apply(this, args)//调用Game的this,并传递参数
}
LOL.prototype =Object.create(Game.prototype)//关键点
LOL.prototype.constructor = LOL
const game5 = new LOL('args')//调用
###拔高:如何实现多重继承?
function Game(args) {
this.name = 'lol'
this.skin = ['s']
}
Game.prototype.getName = function () {
return this.name
}
function Store() {
this.shop = 'steam'
}
Game.prototype.getPlatform = function () {
return this.shop
}
function LOL(args) {
Game.apply(this, args)//调用Game的this,并传递参数
Store.apply(this, args)
}
LOL.prototype = Object.create(Game.prototype)//关键点
// Store.prototype =Object.create(Game.prototype)会冲掉 LOL.prototype
Object.assign(Store.prototype, LOL.prototype)
LOL.prototype.constructor = LOL