那么,对于多层次类型的构造函数情况又如何呢?
我们再来看下面的代码:
1 function Person(name) //基类构造函数
2 {
3 this.name = name;
4 };
5
6 Person.prototype.SayHello = function() //给基类构造函数的prototype 添加方法
7 {
8 alert("Hello, I'm " + this.name);
9 };
10
11 function Employee(name, salary) //子类构造函数
12 {
13 Person.call(this, name); //调用基类构造函数
14 this.salary = salary;
15 };
16
17 Employee.prototype = new Person(); //建一个基类的对象作为子类原型的原型,
这里很有意思
18
19 Employee.prototype.ShowMeTheMoney = function() //给子类添构造函数的pr
ototype 添加方法
20 {
21 alert(this.name + " $" + this.salary);
22 };
23
24 var BillGates = new Person("Bill Gates"); //创建基类Person 的BillGates 对象
25 var SteveJobs = new Employee("Steve Jobs", 1234); //创建子类Employee
的SteveJobs 对象
26
27 BillGates.SayHello(); //通过对象直接调用到prototype 的方法
21
28 SteveJobs.SayHello(); //通过子类对象直接调用基类prototype 的方法,关注!
29 SteveJobs.ShowMeTheMoney(); //通过子类对象直接调用子类prototype 的方法
30
31 alert(BillGates.SayHello == SteveJobs.SayHello); //显示:true,表明prototyp
e 的方法是共享的
这段代码的第17 行,构造了一个基类的对象,并将其设为子类构造函数的prototype,这是很有意思的。这样做的目的就是为了第28 行,通过子类对象也可以直接调用基类prototype 的方法。为什么可以
这样呢?原来,在 JavaScript 中,prototype 不但能让对象共享自己财富,而且prototype 还有寻根问祖的天性,从而使得先辈们的遗产可以代代相传。当从一个对象那里读取属性或调用方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的prototype 对象那里寻找;如果prototype 没有,又会去prototype 自己关联的前辈prototype 那里寻找,直到找到或追溯过程结束为止。
在 JavaScript 内部,对象的属性和方法追溯机制是通过所谓的prototype 链来实现的。当用new 操作符构造对象时,也会同时将构造函数的prototype 对象指派给新创建的对象,成为该对象内置的原型对象。对象内置的原型对象应该是对外不可见的,尽管有些浏览器(如Firefox)可以让我们访问这个内置原型对象,但并不建议这样做。内置的原型对象本身也是对象,也有自己关联的原型对象,这样就形成了所谓的原型链。
在原型链的最末端,就是Object 构造函数prototype 属性指向的那一个原型对象。这个原型对象是所有对象的最老祖先,这个老祖宗实现了诸如toString 等所有对象天生就该具有的方法。其他内置构造函数,如Function, Boolean, String, Date 和RegExp 等的prototype 都是从这个老祖宗传承下来的,但他们各自又定义了自身的属性和方法,从而他们的子孙就表现出各自宗族的那些特征。
这不就是 “ 继承 ” 吗?是的,这就是 “ 继承 ” ,是 JavaScript 特有的 “ 原型继承 ” 。