面相对象
对象是什么?为什么面相对象?优势?
简化了我们对于流程的岔路准备
特点:逻辑迁移更加灵活,代码复用性更高,高度模块化(利于整体维护)
对象的理解
- 对象是对单个物体的简单抽象 => 两个对象产生关联
- 对象是基础,对象也是容器 => 对象可以存放属性,方法,对象
=> 属性
=> 方法
//简单对象 - 本身开放
//一个对象仅代表一个
const Course = {
teacher:'yy',
class:'oop',
startCourse:function(name){
return `开始${name}课程`
}
}
Course.teacher
Course.class
Course.startCourse()
//函数对象(类群的概念)
function Course(){
this.teacher = 'yy',
this.class = 'oop',
this.startCourse = function(name){
return `开始${name}课程`
}
}
const course1 = new Course()
//构造实例的函数对象 => 构造函数 => 严谨化构造一个函数
//=> es => class
构造函数 - 功能:生成对象
- 需要一个模版
- 类即对象模版
- js对象的本质并不是直接基于类,基于构造函数 + 原型链传递方式 => constructor + prototype
问:
new的过程发生了什么?new是什么?new的原理?
function Course(){}
const course = new Course()
- 1.结构上:创建了一个空对象,用于承载返回的对象实例
- 2.属性上:生成的空对象的原型对象指向了构造函数的prototype属性
- 3.关系上:将当前的实例对象赋给了内部的this
- 4.生命周期上:执行了构造函数的初始化代码
问:实例化生成的对象彼此之间有没有直接联系? - 相互独立,没有联系
function Course(teacher){
this.teacher = teacher,
this.class = 'oop',
this.startCourse = function(name){
return `开始${name}课程`
}
}
//传参独立
const course1 = new Course('yy')
const course2 = new Course('zz')
//属性独立
course2.teacher = 'wyz'
问:constructor 他的存在意义?是什么? => 构造一类物品的模块
-
1.每个实例对象被创建时,会自动拥有一个证明身份的属性constructor
-
2.constructor来自于原型对象,指向了构造函数的引用
-
实例获得类的属性 => 继承了类的属性
问:使用构造函数创建对象就没有问题了吗?会有性能上的问题?
=> 如何进行优化?前面提到的原型对象又是什么呢?
原型对象
course2.__ptoto__ === Course.prototype //true
-
每个实例创建时都具备一个constructor
-
constructor & 继承属性 来自于new => 形成了属性传递的链条
-
子类上生成__proto__,将prototype放入 => 形成原型链
-
原型链传递的原理 => Course.prototype
function Course(teacher){
this.teacher = teacher,
this.class = 'oop',
this.startCourse = function(name){
return `开始${name}课程`
}
}
//有共同的属性和方法可以挂载在父级的prototype上,形成节约
Course.prototype.startCourse = function(name){
return `开始${name}课程`
}
const course1 = new Course('yy')
const course2 = new Course('zz')
继承
实现继承 => 在原型对象中的属性和方法都可以被孩子继承
function Game(){
this.name = 'LOL'
}
Game.prototype.gameName = function(){
return this.name
};
function LOL(){};
LOL.prototype = new Game();
LOL.prototype.constructor = LOL;
const lol = new LOL();
lol.getName();
问:重写原型的方式,缺点?
function Game(){
this.name = 'LOL';
this.skin = ["s"];
}
Game.prototype.gameName = function(){
return this.name
};
function LOL(){};
LOL.prototype = new Game();
LOL.prototype.constructor = LOL;
const lol1 = new LOL();
const lol2 = new LOL();
lol1.skin.push("ss")
console.log(lol1.skin); // ["s","ss"]
console.log(lol2.skin); // ["s","ss"]
- 1.因为父类的属性一旦赋值给子类的原型属性,此时就属于子类实例共享了 - 继承者的实例间篡改
- 实例化时,无法向父类进行传参
解决方案:构造函数继承
经典继承 - 构造函数内部的调用
function Game(){
this.name = 'LOL';
this.skin = ["s"];
}
Game.prototype.gameName = function(){
return this.name
};
function LOL(arg){
Game.call(this,arg)
};
const lol1 = new LOL();
const lol2 = new LOL();
lol1.skin.push("ss")
//解决共享属性问题 + 传参问题
问:原型链上的共享方法就无法读取继承?怎么解决?
function Game(){
this.name = 'LOL';
this.skin = ["s"];
}
Game.prototype.gameName = function(){
return this.name
};
function LOL(arg){
Game.call(this,arg)
};
LOL.prototype = new Game();
LOL.prototype.constructor = LOL;
const lol1 = new LOL();
const lol2 = new LOL();
lol1.skin.push("ss")
//解决拿不到原型链上共享方法问题
问:父类的构造函数会被执行两遍,怎么办?
寄生组合继承
function Game(){
this.name = 'LOL';
this.skin = ["s"];
}
Game.prototype.gameName = function(){
return this.name
};
function LOL(arg){
Game.call(this,arg)
};
LOL.prototype = Object.create(Game.prototype);
LOL.prototype.constructor = LOL;
问:多重继承?
function Game(){
this.name = 'LOL';
this.skin = ["s"];
}
Game.prototype.gameName = function(){
return this.name
};
function Store(){
this.shop = 'epic';
}
Store.prototype.getPlatform = function(){
return this.shop
}
function LOL(arg){
Game.call(this,arg)
Store.call(this,arg)
};
LOL.prototype = Object.create(Game.prototype);
//优先级
Object.assign(LOL.prototype,Store.prototype)
LOL.prototype.constructor = LOL;
拔高
对象 => 转化成模块
闭包 => 突破作用域
=> 隔离 + 和外部关联的桥梁
面试:如何实现一个私有变量
function createStack(){
return {
item:[],
push(item){
this.item.push(item)
}
}
}
function createStack(){
//私有变量
const item = []
//形成独立作用域 + 模块
return {
push(item){
items.push(item)
}
setItem(){}
getItem(){
return items
}
}
}
function Main(){
this.createStack = reacteStack
}
const main = new main()
main.createStack().getItem()
//封装