面向对象系列之二
面向对象系列
1. 面向对象的三大特性
- 封装性: 将复杂的实现过程包装、隐藏起来,给用户提供使用接口。
- 继承性: 在js中,继承是体现在对象与对象之间的关系,继承就是指一个对象有权去访问别的对象上的成员。
- 多态性: 体现在子对象和父对象之间: 在父对象上的同一个行为,在各个子对象中的具体实现不同。
code show time:
code block:
123456
var date = new Date;console.log(date.toString());var arr = [1, 3, 5];console.log(arr.toString());var o = {name: 'shelly'};console.log(o.toString());
在这个里头你就可以看出相同的一个函数,在不同的调用结果就是不一样的,所以在js之中,多态就是 函数的重载和重写
2. 继承的实现方式:
- 基于原型
a: 扩展原型 : 在原有的原型上进行相应的扩展,实现继承。
1234567891011// 1>基于原型a: 基于原型: 扩展原型function A() {}var a = new A;A.prototype.printA = function() {console.log('a');};a.printA();// aa -> A.prototypeb: 置换原型:将要被继承的对象,直接替换掉原有的原型,实现继承
|
|
- 拷贝继承:
将指定对象上的所有成员拷贝一份,并添加到当前对象上。这种继承方式成为拷贝继承。12345678910111213141516171819202122232425262728// 2> 拷贝继承:将别的对象上的所有成员拷贝一份,添加到当前对象本身。var parent = {print: function() {console.log('i am ' + this.name);},name: 'parent'};var child = {name: 'child'};// 1: 遍历parentfor (var k in parent) {// 2: 将parent对象上的成员添加到child上。child[k] = parent[k];}child.print();var parent1 = {print1: function() {console.log('print1');}};for (var k in parent1) {// 2: 将parent对象上的成员添加到child上。child[k] = parent1[k];}// 封装// 封装为child对象一个方法extend,谁调用extend方法就是给谁实现继承。child.print1();
非常的麻烦所以就有了extend
- 对象冒充: 在一个构造函数中,可以动态的添加一个parent方法,指向已有的构造函数,然后掉用parent方法去实例化当前对象的
一部分成员(或全部成员)。此时这种方式被称为对象冒充。
1234567891011121314function parent(name, age, gender) {this.name = name;this.age = age;this.gender = gender;}function child(name, age, gender, address) {this.parent = parent;this.parent(name, age, gender);delete this.parent;this.address = address;}var c = new child('xiaoming', 20, 'girl', 'china');console.log(c);
注意 :利用完parent属性之后,记得删除该属性。
在实际开发中,两种继承方式可以组合起来应用。
3. extend方法的实现: 为了方便去实现拷贝继承。
|
|
4. ES5 Object.create : 通过置换原型的方式来实现继承。
|
|
|
|
5. 原型链的概念
- 几个默认
- a: 所有对象都有proto属性,这个属性引用它的原型对象。
- b: 原型对象继承自Object.prototype,具有constructor属性;如果置换了原型,记得要添加constructor属性。
- c: 只有函数具有prototype属性(除了Function.prototype)。
- 概念:从当前对象到Object.prototype之间,存在一条层次分明,逐级递进的体现继承关系的链式结构
== 这个结构被称为原型链。==
6. 属性搜索原型: 当访问对象成员时
- 首先,在当前对象上查找,如果找到就直接返回(调用),停止查找;
- 如果没有找到,就向其原型对象上查找;如果找到就直接返回(调用),停止查找;
- 如果没有找到,就继续向原型对象的原型对象上查找,直到Object.prototype;
- 如果找到,那么就直接返回(调用),并停止查找;否则返回undefined(报错:xxx is not a function)
*注意
- 如果访问对象的某个属性不存在的话,会搜索整个原型链。会导致js性能降低。
- 在实际开发中,尽量保持一个适度的原型链长度。
- 兼顾js性能以及代码的可读性可扩展性。
7. Object.prototype介绍
hasOwnProperty:判断当前对象的指定属性是否为自身的,而不是继承过来的;如果是本身的返回true;否则返回false。
1234567语法:<object>.hasOwnProperty('propName')has: 有own:自己Property : 属性var o = {name: 'tom'};console.log(o.hasOwnProperty('name')); // trueconsole.log(o.hasOwnProperty('toString')); // falseisPrototypeOf:判断当前对象是否为指定对象的原型对象。如果是返回true;否则返回false。
1234567891011121314语法;<a>.isPrototypeOf(<b>);<!-- 只要对象a出现在b对象的原型链上就返回true;否则返回false。 -->function A() {}function B() {}var a = new A;B.prototype = a;var b = new B;console.log(a.isPrototypeOf(b)); // false;console.log( A.prototype.isPrototypeOf(b));// b -> a -> A.prototype -> Object.prototype -> nullconsole.log(Object.prototype.isPrototypeOf(a));console.log(Object.prototype.isPrototypeOf(b));如果当前对象出现在指定对象的原型链上就返回true;否则返回false。
propertyIsEnumerable:即判断指定属性是否为自身的,并且该属性也是可枚举的
只有这两个条件都满足才返回true;否则返回false。
- // 可枚举?for in遍历出来的属性都是可枚举的。
- // 默认:手动添加属性都是可枚举的,js解析器自动添加的都是不可枚举。
8. 构造函数的执行过程
- 创建了一个空对象obj;
- 将obj赋值给this(让this指向obj)
- 将当前作用域交给this
- 执行构造函数内部的代码
- 将 this 返回。(return this;)
|
|
9. 绘制对象的原型链
绘制规则:
- 绘制出简化的原型链
- 先将上述简化的原型链上的每一个对象绘制在图形上。
- 将每一个对象的默认属性添加上。
- 给每一个对象的属性添加指向。
- 如果每一个对象的属性都有了指向,说明原型链绘制完成。