2016-09-03-day12 am
面向对象的理解:
面向对象三大特点:
封装:将一个/一类事物的属性和功能集中定义在一个对象中 (为了代码重用!)
继承:父对象中的成员,子对象无需重复创建,即可直接使用。(为了即代码重用,又节约内存)
多态:同一个方法,在不同情况下,表现出不同的状态。(为了体现子对象与父对象之间的差异。)
继承: js中的继承都是通过原型对象实现的,也称之为原型继承/继承原型。
1.原型对象(prototype):
- 什么是原型对象:集中存储一类对象共有成员的父对象。
- 何时用原型对象: 只要多个子对象中,拥有相同的成员,就都要集中定义在父对象(原型对象)中一份,然后所有子对象共用!
- 如何用原型对象:
1.如何创建: 在创建构造函数时,会自动创建该类型的原型对象prototype
2.何时继承: new的第二步,设置新对象的__proto__
属性继承构造函数的原型对象
3.如何向原型对象中添加共有成员:类型名.prototype.共有成员名=值
2.原型链: 由各级父对象逐级继承,实现的链式结构。
任何对象都由__proto__
继承其父对象
Object.prototype是所有对象的顶级父对象。
Object.prototype.__proto__
是null
Function.prototype是所有函数对象的父对象。Function.prototype.__proto__
是Object.prototype
原型链控制着成员的使用顺序:
优先使用当前对象本地的自有成员
如果自己没有,才延原型链向父级找
如果到Object.prototype没找到,返回undefined。
3.正确的访问对象的成员:
原则: 修改原型链上的共有成员:必须用父对象改。修改自有成员: 必须用当前子对象本身。禁止使用子对象修改共有成员
4.如何判断成员是自有还是共有:
自有: 直接定义在当前对象本地的成员
共有: 对象本地没有,从原型链上继承来的成员。
判断自有:
//判断"成员名"是否直接定义在obj本地
var bool=obj.hasOwnProperty("成员名")
//如果是自有,就返回true,
//否则返回false
判断共有:
不是自有,且原型链上有
!obj.hasOwnProperty("成员名")&&(obj.成员!==undefined)
//或
"成员名" in obj
注:in: 判断"成员名"是否包含在obj的原型链上。(可检查整个原型链)
5.删除: delete obj.属性名
注:不能用子对象删除共有属性
pm
1.扩展内置对象的API:
- 为什么: 解决浏览器兼容性问题
- 何时: 如果想在旧的浏览器上,使用新浏览器的API,就需要再旧浏览器扩展内置对象的API
- 如何: 都是将自定义的API添加到指定类型的原型对象上。
2.原型API:
2.1获得原型对象:2种:
通过构造函数获得: 构造函数.prototype
通过子对象获得: obj.__proto__
兼容性
Object.getPrototypeOf(obj)
获得obj对象的父对象(原型对象)
2.2判断指定对象是否是子对象的父对象:
father.isPrototypeOf(child)
,判断father对象,是否是child对象的父对象。
如果father是child的父对象,就返回true,否则返回false
强调: 检查整个原型链
2.3判断指定对象是否是指定构造函数的实例:
child instanceof 构造函数(mather)
,判断child是不是被构造函数实例化出的
强调: 也检查整个原型链
2.4鄙视题: 判断一个对象是不是数组类型, 有几种办法?
typeof: 只能识别原始类型和函数,无法进一步区分不同的引用类型
1.isPrototypeOf
2.instanceof
3.class属性
: 记录了对象创建时的类型名,一旦对象创建,不可更改,只有Object.prototype中的toString方法才能输出class属性
问题: 内置对象的原型对象中都重写了新的toString方法,阻碍了子对象直接调用原始的toString方法
解决: 用call强行调用!要调用方法的完整签名.call(调用方法的对象)
4.Array.isArray(obj)
,专门用于检测obj是不是数组类型,原理同第三种方法
总结:
call: 用一个对象强行调用一个本来无法调用到的函数。
何时: 希望打破原型链的限制,直接调用一个本不可调用的函数
如何: 要调的函数.call(对象)
添加一个新方法,如何选择加在构造函数上,或者加在原型对象中?
如果希望指定类型的所有子对象都可访问时,就放在原型对象中——必须通过实例化的对象调用(也成为实例方法)
如果无法确定将来调用函数时的对象的类型,就不能放在原型对象中。要放在构造函数上。——static静态方法
3.多态:
重写(override): 如果子对象觉得父对象继承来的成员不好用,就可在本地定义和父对象成员同名的自有成员。优先使用自有成员,而屏蔽了父对象的共有成员。
1. 自定义继承(3种方法):
1). 修改一个对象继承另一个父对象:
child.__proto__=father;
=> Object.setPrototypeOf(
child,father
)
//设置child继承father
2). 批量修改所有子对象的父对象:
时机: 在开始创建子对象之前,就修改原型对象。
构造函数.prototype=father
3). 两种类型间的继承:
问题: 两种类型间,有部分相同的属性结构,和共同的方法。
解决: 抽象出一个公共的父类型
将子类型中相同的部分属性和方法,定义到父类型中。
如何实现两种类型间的继承:
1)). 设置子类型的原型对象继承父类型的原型对象。
Object.setPrototypeOf(
子类型的原型对象,
父类型的原型对象
);
2)). 借用父类型的构造函数: 父类型构造函数.call(this,参数,...)