对象是什么?为什么要面向对象?
特点:面向对象-------逻辑迁移更灵活,代码复用性高,高度的模块化
对象分为简单对象和函数对象(即构造函数)
构造函数
function Course(teacher) {
this.teacher = teacher
this.course = 'oop'
this.startCourse = function() {
// start
}
}
const course = new Course('yy')
const course1 = new Course('zz')
Course本质就是构造函数
1、函数体内使用的this,指向索要生成的示例
2、生成对象需要使用new来进行实例化
3、可以做初始化参数
如果构造函数不初始化,可以使用吗? - 无法使用
如果项目中需要使用,通常(不被外界感知)如何解决?
let staticProps = undefined
function Course1() {
const _isClass = this instanceof Course
if (!_isClass) {
staticProps = new Course()
return staticProps
} else {
return staticProps
}
}
function Course() {
this.teacher = 'aaa'
this.course = 'oop'
this.startCourse = function() {
// start
}
}
// 使用方
const course = Course1()
// 暴露出去的是实例,而将实例化的过程放置在下层不被上层所感知
-
启发:如果写底层代码时,不需要让外界熟悉感知内部代码思想
-
延伸:通过改进 => 多次实例化,同一个实例 => 单例模式
思考:new是什么? / new的原理 / new时候做了些什么?
- 结构上:创建了一个空对象,做为返回的对象实例
- 属性上:将生成的空对象和类产生了关联 => prototype
- 将生成的对象的原型对象指向了构造函数的prototype属性
- 关系上:将当前实例对象赋给了内部this
- 声明上:构造函数初始化代码的执行
constructor 是什么?
- 每个对象在创建的时候,会自动拥有一个构造函数的属性constructor
- constructor继承自原型对象,指向了构造函数的引用 => 实例获得了类的属性 => 继承了类的属性
原型对象
- 构造函数 - 赋予一个属性prototype,该属性引用等于实例对象的proto course1.proto === Course.prototype
- 实例对象 - 每一个实例对象都有个constructor => 指向当前构造函数 course1.constructor === Course
- prototype是什么?
- 解决构造函数性能上的问题:把重复使用到的属性或者方法写在构造函数的原型对象prototype上
继承
在原型对象中的所有属性和方法,都能被实例所共享
// game类
function Game() {
this.name = 'lol'
this.skin = ['s']
}
Game.prototype.getName = function() {
return this.name
}
// LOL类
function LOL() {}
LOL.prototype = new Game()
//父类始终是LOL,所以要多做一步
LOL.prototype.constructor = LOL
const game1 = new LOL()
// 扩展
const game2 = new LOL()
game1.skin.push('ss')
-
- 父类属性一旦复制给子类的原型属性,此时属性属于子类的共享属性了
- 实例化子类的时候,无法向父类传参
解决方法:构造函数继承
在子类的构造函数内部调用父类构造函数
// game类
function Game(arg) {
this.name = 'lol'
this.skin = ['s']
}
Game.prototype.getName = function() {
return this.name
}
// LOL类
function LOL(arg) {
Game.call(this, arg)
}
const game3 = new LOL('arg')
// 解决共享属性 + 子向父传参的问题
追问:原型链上的共享方法无法被读取继承 => 组合继承
// game类
function Game(arg) {
this.name = 'lol'
this.skin = ['s']
}
Game.prototype.getName = function() {
return this.name
}
// LOL类
function LOL(arg) {
Game.call(this, arg)
}
LOL.prototype = new Game()
LOL.prototype.constructor = LOL
const game3 = new LOL('arg')
追问:组合继承就没有缺点么?问题在于:无论在何种场景下,都会调用两次父类构造函数 => 寄生组合继承
function Game(arg) {
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
提高:如何去实现多重继承? => 原型属性合并
function Game(arg) {
this.name = 'lol'
this.skin = ['s']
}
Game.prototype.getName = function() {
return this.name
}
function Store() {
this.shop = 'steam'
}
Store.prototype.getPlatform = function() {
return this.shop
}
function LOL(arg) {
Game.call(this, arg)
Store.call(this, arg)
}
LOL.prototype = Object.create(Game.prototype)
// LOL.prototype = Object.create(Store.prototype)
Object.assign(LOL.prototype, Store.prototype)
LOL.prototype.constructor = LOL