Java辅导:悟透JavaScript三)
来源:优易学  2011-11-26 16:18:19   【优易学:中国教育考试门户网】   资料下载   IT书店

  初看原型

  prototype源自法语,软件界的标准翻译为“原型”,代表事物的初始形态,也含有模型和样板的意义。JavaScript中的prototype概念恰如其分地反映了这个词的内含,我们不能将其理解为C++的prototype那种预先声明的概念。

  JavaScript 的所有function类型的对象都有一个prototype属性。这个prototype属性本身又是一个object类型的对象,因此我们也可以给这个prototype对象添加任意的属性和方法。既然prototype是对象的“原型”,那么由该函数构造出来的对象应该都会具有这个“原型”的特性。事实上,在构造函数的prototype上定义的所有属性和方法,都是可以通过其构造的对象直接访问和调用的。也可以这么说,prototype提供了一群同类对象共享属性和方法的机制。

  我们先来看看下面的代码:

  function Person(name)

  {

  this.name = name;   //设置对象属性,每个对象各自一份属性数据

  };

  Person.prototype.SayHello = function()  //给Person函数的prototype添加SayHello方法。

  {

  alert("Hello, I'm " + this.name);

  }

  var BillGates = new Person("Bill Gates");   //创建BillGates对象

  var SteveJobs = new Person("Steve Jobs");   //创建SteveJobs对象

  BillGates.SayHello();   //通过BillGates对象直接调用到SayHello方法

  SteveJobs.SayHello();   //通过SteveJobs对象直接调用到SayHello方法

  alert(BillGates.SayHello == SteveJobs.SayHello); //因为两个对象是共享prototype的SayHello,所以显示:true

  程序运行的结果表明,构造函数的prototype上定义的方法确实可以通过对象直接调用到,而且代码是共享的。显然,把方法设置到prototype的写法显得优雅多了,尽管调用形式没有变,但逻辑上却体现了方法与类的关系,相对前面的写法,更容易理解和组织代码。

  那么,对于多层次类型的构造函数情况又如何呢?

  我们再来看下面的代码:

  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()  //给子类添构造函数的prototype添加方法

  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的方法

  28     SteveJobs.SayHello();       //通过子类对象直接调用基类prototype的方法,关注!

  29     SteveJobs.ShowMeTheMoney(); //通过子类对象直接调用子类prototype的方法

  30

  31     alert(BillGates.SayHello == SteveJobs.SayHello); //显示:true,表明prototype的方法是共享的

  这段代码的第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特有的“原型继承”。

  “原型继承”是慈祥而又严厉的。原形对象将自己的属性和方法无私地贡献给孩子们使用,也并不强迫孩子们必须遵从,允许一些顽皮孩子按自己的兴趣和爱好独立行事。从这点上看,原型对象是一位慈祥的母亲。然而,任何一个孩子虽然可以我行我素,但却不能动原型对象既有的财产,因为那可能会影响到其他孩子的利益。从这一点上看,原型对象又象一位严厉的父亲。我们来看看下面的代码就可以理解这个意思了:

  function Person(name)

  {

  this.name = name;

  };

  Person.prototype.company = "Microsoft"; //原型的属性

  Person.prototype.SayHello = function()  //原型的方法

  {

  alert("Hello, I'm " + this.name + " of " + this.company);

  };

  var BillGates = new Person("Bill Gates");

  BillGates.SayHello();   //由于继承了原型的东西,规规矩矩输出:Hello, I'm Bill Gates

  var SteveJobs = new Person("Steve Jobs");

  SteveJobs.company = "Apple";    //设置自己的company属性,掩盖了原型的company属性

  SteveJobs.SayHello = function() //实现了自己的SayHello方法,掩盖了原型的SayHello方法

  {

  alert("Hi, " + this.name + " like " + this.company + ", ha ha ha ");

  };

[1] [2] 下一页

责任编辑:小草

文章搜索:
 相关文章
热点资讯
资讯快报
热门课程培训