面向对象三大特点: 封装 继承 多态
为什么继承: 代码重用! 节约内存空间!
何时继承: 只要多个子对象共用的属性和方法,都要集中定义在父对象中
js中的继承,都是通过原型实现的——继承原型
什么是原型: 保存一类子对象共有属性和方法的父对象
所有子对象都自动继承原型对象
每个构造函数都有一个prototype属性,应用自己的原型对象。
new4步:
1. 窗机空对象
2. 设置新对象的父对象为构造函数的原型对象
3. ...
4. ...
对象成员的访问规则:
1. 先在对象本找自有属性
2. 如果自己没有,就自动通过__proto__找原型对象的
自有属性和共有属性:
自有属性: 保存在对象本地的属性
共有属性: 保存在父对象中的属性,所有子对象共有
判断自有和共有属性:
1. 判断自有属性: obj.hasOwnProperty("属性名")
如果返回true,说明"属性名"是obj的自有属性
如果返回false,有两种可能: 共有或没有
2. 判断共有属性: 2个条件:
1. 不是自有: hasOwnProperty返回false
2. 在原型链上包含: "属性名" in 对象
检测"属性名"是否定义在对象的原型链上
if(obj.hasOwnProperty("属性名")==false
&&"属性名" in obj){
是共有属性
}
原型链: 由各级对象,通过__proto__逐级继承,实现的链式继承关系。
只要在原型链上包含的成员,子对象都可继承!
修改或删除属性:
1. 修改或删除自有属性:
修改: obj.属性名=新值
删除: delete obj.属性名
2. 修改或删除共有属性:
不能用子对象直接操作!
如果用子对象操作:
1. 修改: obj.共有属性=新值 ——危险
结果: 在obj本地添加同名的自有属性
覆盖父对象的共有属性
2. 删除: delete obj.共有属性; ——无效
要想修改和删除共有属性,只能通过原型对象本身
解决浏览器兼容性问题:
所有内置对象,几乎都有构造函数和原型对象
只有Math没有构造函数
构造函数用于创建内置对象的实例: new 构造函数(...);
内置对象的原型对象: 保存了所有内置对象可用的API
判断浏览器不支持指定API:
比如: 判断Array类型不支持indexOf
if(Array.prototype.indexOf===undefined){
Array.prototype.indexOf=function(value,fromi){
}
}
测试:
str.indexOf("kword",fromi)
*****判断一个对象是不是数组:
1. typeof无法区分对象和数组,返回都是object
2. 判断当前对象是否继承自Array.prototype
Array.prototype.isPrototypeOf(obj)
如果返回true,说明是数组,否则不是数组
3. obj instanceof 构造函数
判断obj是否是构造函数的实例
也可检查整个原型链
4. 输出对象的字符串形式:
在Object的prototype中保存着原始的toString方法
原始的toString,默认输出[object Class]
***重写(override):子对象觉得父对象的成员不好用,可在本地定义同名成员,覆盖父对象中的成员。
属于多态的一种
借用函数: 使用另一个对象,临时调用指定的函数
函数中的this,被替换为了临时对象
函数.call(临时对象) 相当于: 临时对象.函数()
5. Array.isArray(obj)
****实现自定义继承:
1. 实现两个对象间的继承:
子对象.__proto__=父对象 //可能禁止访问内部属性
兼容: Object.setPrototypeOf(子对象,父对象)
让子对象继承父对象
2. 通过修改构造函数的原型对象来修改多个子对象的父对象
时机: 应该在开始创建对象前!
*****3. 既继承(inherit)对象,又扩展(extends)结构
2步:
1. 借用父类型构造函数
父类型构造函数.apply(this,arguments);
*****call vs apply
功能完全一样,都是借用函数,并传入参数
差别: call,要求分散传入参数
apply,要求将参数放在集合中传入
2. 让子类型的原型,继承父类型的原型
Object.setPrototypeOf(
子类型.prototype,父类型.prototype
)