1. 什么是面向对象:
程序中都是用对象来描述现实中一个具体事物
什么是对象:
专门描述现实中一个事物的属性和功能的程序结构——用途
内存中同时保存一个事物的属性和功能的引用类型的存储空间——存储
为什么: 当数量大时,将同一个事物的多个属性和功能,集中起来存放,便于查找和使用。
何时: 只要在程序中描述一个事物,都要用对象结构。
面向对象三大特点: 封装,继承,多态
2. 封装:
什么是: 将一个事物的属性和功能集中定义在一个对象结构中
事物的属性会成为对象中的属性,其实就是保存在对象中的变量
事物的功能会成为对象的方法,其实就是保存在对象中的函数
为什么: 便于维护和查找
何时: 只要使用面向对象的方式编程,都要先将要管理的事物封装在一个对象中,再使用对象管理事物。
如何: 3种:
1. 对象直接量:
var obj={
属性名:值,
… : … ,
//方法名:function(){
方法名(){//ES6
…
}
}
何时: 只要定义对象时,已经知道对象的成员
问题: 对象的方法中属性值不能写死,应该动态获得当前对象自己的属性变量
解决: 错误: 在方法中仅写属性变量名
解决: 对象名.属性名
问题: 如果对象名变化,需要同时修改方法内写死的对象名——不便于维护
解决: this: 自动指向正在调用函数的.前的对象,可根据对象名称自动获取当前对象名。
总结: 今后只要对象自己的方法,要使用自己的属性,必须用this.属性名。
2. 用new:
var object=new Object();
object.属性名=值;
… . … = …;
object.方法名=function(){
…this.属性名…
}
何时: 如果定义对象时,暂时不知道对象的成员。
对象的本质: js中的对象底层其实就是关联数组
只不过,用法比数组简化。
问题: 反复创建相同类型的多个对象时,代码冗余量太大——不便于维护
解决: 在反复创建对象前,先定义一类对象的统一结构图——构造函数:
3. 用构造函数反复创建多个相同结构的对象
什么是构造函数: 专门描述一类对象统一结构的函数。——设计图
为什么: 代码重用!
何时: 只要反复创建同一类型的多个对象前都要先用构造函数定义同一类型的统一结构
如何: 2步:
1. 定义构造函数:
function 类型名(属性参数列表){
this.属性名=属性参数;
this. … = …;
this.方法名=function(){
…this.属性名…
}
}
2. 用构造函数反复创建多个对象:
var obj=new 类型名(属性值列表);
new:
1. 创建一个空对象:
2. 让新对象自动继承构造函数的原型对象
设置新对象的__proto__属性继承原型对象
3. 调用构造函数并让构造函数的this->新对象
执行过程中: this.新属性=属性变量
会强行向空对象中依次添加规定的新属性,并将属性参数值保存到对象的新属性中——装修
4. 将新对象的地址返回到变量中保存
访问对象的成员: 成员=属性+方法
访问属性: obj.属性名 —— 用法同变量
的
调用方法: obj.方法名() —— 用法同函数
问题: 将方法定义放在构造函数内,每new一个新对象,都会重复创建相同方法定义的副本——浪费内存
解决:
3. 继承:
什么是: 父对象中的成员,子对象无需重复创建,可直接使用!
何时: 今后,只要多个子对象拥有相同的属性值和方法定义时,只要仅在父对象中定义一份,所有子对象共用即可!
为什么: 代码重用, 节约内存
如何: 继承关系都是默认的,不用自己创建
每创建一个构造函数,赠一个原型对象prototype
什么是原型对象: 专门保存同一类型的多个子对象共有成员的父对象
何时使用: 只要同一类型的多个子对象,共有的成员都要放在构造函数的原型对象中
用构造函数每创建一个子对象就会自动设置子对象继承构造函数的原型对象
如何使用: 凡是同一类型子对象共有的成员都要放在原型对象中
构造函数.prototype.成员=值
从此构造函数中不再包含方法定义
自有属性和共有属性:
自有属性: 直接保存在对象本地的属性
共有属性: 保存在父对象中,由多个子对象共享的属性
获取: 两者完全相同: 对象.属性
顺序: 先在对象本地找自有属性
自己没有才去父对象找
修改: 自有属性: 子对象.属性=值
共有属性: 不能使用子对象修改
必须: 构造函数.prototype.属性名=值
原型链:
什么是: 由多级父元素逐级继承形成的链式结构
保存着: 所有对象的属性和方法
控制着: 对象成员的使用顺序:
先用自有,自己没用,才去父级找
vs 作用域链:
保存着: 所有不属于任何对象的变量
控制着: 变量的使用顺序:
先用局部,局部没有,才去父级作用域中找
访问:
作用域链中的变量,不用.可直接访问
原型链中的对象属性,必须用obj.属性才能访问
内置对象的原型对象:
凡是能new的其实都是构造函数
比如: function Array(){…}
function Date(){…}
只要是构造函数,都附赠原型对象
比如: Array.prototype
Date.prototype
其实所有API都是保存在内置对象的原型对象中,所有子对象自动继承使用!
比如: Array.prototype.sort()/push()/slice()….
Date.prototype.getDate()/getTime()/setMonth()…
特殊:
问题: 旧浏览器无法使用新的API:
原因: 旧浏览器的内置对象的原型对象中不包含想要的API
解决: 在浏览器中,判断内置对象的原型对象中是否包含指定API,如果不包含,就向原型对象中手动添加一个。
多态:
什么是: 同一个函数在不同的情况下表现出不同的状态
重写:
什么是: 在子对象中定义和父对象中同名的成员
效果: 使用时,先用子对象自己的成员
相当于屏蔽了父对象中的同名成员
override
为什么: 从父对象中继承来的成员,不一定都是想要的!
何时: 只要从父对象中继承来的成员不是想要的,就都可以重写自己的,覆盖父对象的。
自定义继承:
何时: 只要父对象不是想要的,就可自行修改
如何: 3种
1. 仅修改一个对象的父对象:
child.__proto__=father
问题:__proto__是内部属性,可能不允许使用
解决: Object.setPrototypeOf(child,father);
问题: 一次只能修改一个对象的父对象
2. 修改所有子对象的父对象:
其实就是修改构造函数的prototype属性
构造函数.prototype=father
强调: 时机: 在创建所有子对象之前
3. 两种类型间的继承:
问题: 两种类型间拥有部分相同的属性和功能
解决: 抽象出一个父类型
3步:
1. 定义父类型:
父类型构造函数: 相同的部分属性
父类型原型对象: 相同的部分方法
2. 让子类型原型对象继承父类型原型对象
Object.setPrototypeOf(
子类型.prototype, 父类型.prototype
)
3. 在子类型构造函数内借用父类型构造函数: