Contents
  1. 1. 面向对象系列
    1. 1.1. 1. 面向对象的三大特性
      1. 1.1.1. code show time:
    2. 1.2. 2. 继承的实现方式:
    3. 1.3. 3. extend方法的实现: 为了方便去实现拷贝继承。
    4. 1.4. 4. ES5 Object.create : 通过置换原型的方式来实现继承。
    5. 1.5. 5. 原型链的概念
    6. 1.6. 6. 属性搜索原型: 当访问对象成员时
    7. 1.7. 7. Object.prototype介绍
    8. 1.8. 8. 构造函数的执行过程
    9. 1.9. 9. 绘制对象的原型链

面向对象系列

1. 面向对象的三大特性

  1. 封装性: 将复杂的实现过程包装、隐藏起来,给用户提供使用接口。
  2. 继承性: 在js中,继承是体现在对象与对象之间的关系,继承就是指一个对象有权去访问别的对象上的成员。
  3. 多态性: 体现在子对象和父对象之间: 在父对象上的同一个行为,在各个子对象中的具体实现不同。

code show time:

code block:

1
2
3
4
5
6
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. 继承的实现方式:

  • 基于原型
  1. a: 扩展原型 : 在原有的原型上进行相应的扩展,实现继承。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 1>基于原型
    a: 基于原型: 扩展原型
    function A() {
    }
    var a = new A;
    A.prototype.printA = function() {
    console.log('a');
    };
    a.printA();// a
    a -> A.prototype
  2. b: 置换原型:将要被继承的对象,直接替换掉原有的原型,实现继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// b: 基于原型: 置换原型
function parent() {
this.name = 'tom';
}
parent.prototype.printC = function() {
console.log('c');
console.log(this.name);
};
function child() {
}
child.prototype = new parent;
var c = new child;
c.printC(); // c
// c -> parent实例 -> parent.prototype
var name = new child;
var name = [1, 2, 3];
console.log(typeof name);
// 全局变量都是window对象的属性
// window的name属性只能为字符串
  • 拷贝继承:
    将指定对象上的所有成员拷贝一份,并添加到当前对象上。这种继承方式成为拷贝继承。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // 2> 拷贝继承:将别的对象上的所有成员拷贝一份,添加到当前对象本身。
    var parent = {
    print: function() {
    console.log('i am ' + this.name);
    },
    name: 'parent'
    };
    var child = {
    name: 'child'
    };
    // 1: 遍历parent
    for (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方法去实例化当前对象的
    一部分成员(或全部成员)。此时这种方式被称为对象冒充。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function 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方法的实现: 为了方便去实现拷贝继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1: 一次只能继承一个对象
var child = {};
child.extend = function(parent) {
var k;
for( k in parent ){
this[k] = parent[k];
}
};
child.extend({
name: 'child',
print: function() {
console.log(this.name);
}
});
child.print();
2: 一次实现继承多个对象
child.extend = function() {
var args = arguments,
obj;
// 遍历arguments上的所有对象,依次将遍历的每个对象的成员添加到child。
for( var i = 0, l = args.length;i < l; i++){
obj = args[i];
if( typeof obj === 'object'){ // 判断传入的是否为对象,不是对象就不执行下面代码
for( var k in obj ){
this[k] = obj[k];
}
}
}
};
child.extend({
name: 'child'
}, {
print: function() {
console.log('i am ' + this.name);
}
});
child.print();

4. ES5 Object.create : 通过置换原型的方式来实现继承。

1
2
Object.create(parent)://返回值为一个新的对象,并且该对象继承自parent对象。
var newObject = Object.create(parent);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 兼容问题:
if( !Object.create ){
Object.create = function(parent) {
function F() {}
F.prototype = parent;
return new F;
}
}
var newobj = Object.create({
name: 'tom',
print: function() {
console.log(this.name);
}
});
newobj.print();

5. 原型链的概念

  1. 几个默认
  • a: 所有对象都有proto属性,这个属性引用它的原型对象。
  • b: 原型对象继承自Object.prototype,具有constructor属性;如果置换了原型,记得要添加constructor属性。
  • c: 只有函数具有prototype属性(除了Function.prototype)。
  1. 概念:从当前对象到Object.prototype之间,存在一条层次分明,逐级递进的体现继承关系的链式结构
    == 这个结构被称为原型链。==

6. 属性搜索原型: 当访问对象成员时

    • 首先,在当前对象上查找,如果找到就直接返回(调用),停止查找;
    • 如果没有找到,就向其原型对象上查找;如果找到就直接返回(调用),停止查找;
    • 如果没有找到,就继续向原型对象的原型对象上查找,直到Object.prototype;
    • 如果找到,那么就直接返回(调用),并停止查找;否则返回undefined(报错:xxx is not a function)

*注意

- 如果访问对象的某个属性不存在的话,会搜索整个原型链。会导致js性能降低。
- 在实际开发中,尽量保持一个适度的原型链长度。
- 兼顾js性能以及代码的可读性可扩展性。

7. Object.prototype介绍

  1. hasOwnProperty:判断当前对象的指定属性是否为自身的,而不是继承过来的;如果是本身的返回true;否则返回false。

    1
    2
    3
    4
    5
    6
    7
    语法:<object>.hasOwnProperty('propName')
    has: 有
    own:自己
    Property : 属性
    var o = {name: 'tom'};
    console.log(o.hasOwnProperty('name')); // true
    console.log(o.hasOwnProperty('toString')); // false
  2. isPrototypeOf:判断当前对象是否为指定对象的原型对象。如果是返回true;否则返回false。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    语法;<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 -> null
    console.log(Object.prototype.isPrototypeOf(a));
    console.log(Object.prototype.isPrototypeOf(b));

    如果当前对象出现在指定对象的原型链上就返回true;否则返回false。

  3. propertyIsEnumerable:即判断指定属性是否为自身的,并且该属性也是可枚举的

    只有这两个条件都满足才返回true;否则返回false。
    
    • // 可枚举?for in遍历出来的属性都是可枚举的。
    • // 默认:手动添加属性都是可枚举的,js解析器自动添加的都是不可枚举。

8. 构造函数的执行过程

  1. 创建了一个空对象obj;
  2. 将obj赋值给this(让this指向obj)
  3. 将当前作用域交给this
  4. 执行构造函数内部的代码
  5. 将 this 返回。(return this;)
1
2
3
4
5
6
7
8
9
10
11
12
function Fn(name, age) {
this.name = name;
this.age = age;
}
var fn = new Fn('tom', 18);
console.log(fn);
function Fn(name, age) {
var obj = {};
this = obj;
// Fn.call(this, name, age);(这个可以替代上面的两句话)
return this;
}

9. 绘制对象的原型链

绘制规则:

  1. 绘制出简化的原型链
  2. 先将上述简化的原型链上的每一个对象绘制在图形上。
  3. 将每一个对象的默认属性添加上。
  4. 给每一个对象的属性添加指向。
  5. 如果每一个对象的属性都有了指向,说明原型链绘制完成。
Contents
  1. 1. 面向对象系列
    1. 1.1. 1. 面向对象的三大特性
      1. 1.1.1. code show time:
    2. 1.2. 2. 继承的实现方式:
    3. 1.3. 3. extend方法的实现: 为了方便去实现拷贝继承。
    4. 1.4. 4. ES5 Object.create : 通过置换原型的方式来实现继承。
    5. 1.5. 5. 原型链的概念
    6. 1.6. 6. 属性搜索原型: 当访问对象成员时
    7. 1.7. 7. Object.prototype介绍
    8. 1.8. 8. 构造函数的执行过程
    9. 1.9. 9. 绘制对象的原型链