1、今天在网上看到一篇介绍 javascript 的文章,尽管文章讲述的内容我都很熟悉,但我还是要转载出来让大家读一读,这个哥们的文采真是没的说,能将本来枯燥的程序讲述的如此酣畅淋漓实在让人佩服!原文如下:引子编程世界里只存在两种基本元素,一个是数据,一个是代码。编程世界就是在数据和代码千丝万缕的纠缠中呈现出无限的生机和活力。数据天生就是文静的,总想保持自己固有的本色;而代码却天生活泼,总想改变这个世界。你看,数据代码间的关系与物质能量间的关系有着惊人的相似。数据也是有惯性的,如果没有代码来施加外力,她总保持自己原来的状态。而代码就象能量,他存在的唯一目的,就是要努力改变数据原来的状态。在代码改变
2、数据的同时,也会因为数据的抗拒而反过来影响或改变代码原有的趋势。甚至在某些情况下,数据可以转变为代码,而代码却又有可能被转变为数据,或许还存在一个类似 E=MC2形式的数码转换方程呢。然而,就是在数据和代码间这种即矛盾又统一的运转中,总能体现出计算机世界的规律,这些规律正是我们编写的程序逻辑。不过,由于不同程序员有着不同的世界观,这些数据和代码看起来也就不尽相同。于是,不同世界观的程序员们运用各自的方法论,推动着编程世界的进化和发展。众所周知,当今最流行的编程思想莫过于面向对象编程的思想。为什么面向对象的思想能迅速风靡编程世界呢?因为面向对象的思想首次把数据和代码结合成统一体,并以一个简单的对
3、象概念呈现给编程者。这一下子就将原来那些杂乱的算法与子程序,以及纠缠不清的复杂数据结构,划分成清晰而有序的对象结构,从而理清了数据与代码在我们心中那团乱麻般的结。我们又可以有一个更清晰的思维,在另一个思想高度上去探索更加浩瀚的编程世界了。在五祖弘忍讲授完对象真经之后的一天,他对众弟子们说:“经已讲完,想必尔等应该有所感悟,请各自写个偈子来看”。大弟子神秀是被大家公认为悟性最高的师兄,他的偈子写道:“身是对象树,心如类般明。朝朝勤拂拭,莫让惹尘埃!”。此偈一出,立即引起师兄弟们的轰动,大家都说写得太好了。只有火头僧慧能看后,轻轻地叹了口气,又随手在墙上写道:“对象本无根,类型亦无形。本来无一物,
4、何处惹尘埃?”。然后摇了摇头,扬长而去。大家看了慧能的偈子都说:“ 写的什么乱七八糟的啊,看不懂 ”。师父弘忍看了神秀的诗偈也点头称赞,再看慧能的诗偈之后默然摇头。就在当天夜里,弘忍却悄悄把慧能叫到自己的禅房,将珍藏多年的软件真经传授于他,然后让他趁着月色连夜逃走.后来,慧能果然不负师父厚望,在南方开创了禅宗另一个广阔的天空。而慧能当年带走的软件真经中就有一本是JavaScript 真经!回归简单要理解 JavaScript,你得首先放下对象和类的概念,回到数据和代码的本原。前面说过,编程世界只有数据和代码两种基本元素,而这两种元素又有着纠缠不清的关系。JavaScript 就是把数据和代码都
5、简化到最原始的程度。JavaScript 中的数据很简洁的。简单数据只有 undefined, null, boolean, number 和 string 这五种,而复杂数据只有一种,即 object。这就好比中国古典的朴素唯物思想,把世界最基本的元素归为金木水火土,其他复杂的物质都是由这五种基本元素组成。JavaScript 中的代码只体现为一种形式,就是 function。注意:以上单词都是小写的,不要和 Number, String, Object, Function 等 JavaScript 内置函数混淆了。要知道,JavaScript 语言是区分大小写的呀!任何一个 JavaScr
6、ipt 的标识、常量、变量和参数都只是 unfined, null, bool, number, string, object 和 function 类型中的一种,也就 typeof 返回值表明的类型。除此之外没有其他类型了。先说说简单数据类型吧。undefined: 代表一切未知的事物,啥都没有,无法想象,代码也就更无法去处理了。注意:typeof(undefined) 返回也是 undefined。可以将 undefined 赋值给任何变量或属性,但并不意味了清除了该变量,反而会因此多了一个属性。null: 有那么一个概念,但没有东西。无中似有,有中还无。虽难以想象,但已经可以用代码来处理
7、了。注意:typeof(null)返回 object,但 null 并非object,具有 null 值的变量也并非 object。boolean: 是就是,非就非,没有疑义。对就对,错就错,绝对明确。既能被代码处理,也可以控制代码的流程。number: 线性的事物,大小和次序分明,多而不乱。便于代码进行批量处理,也控制代码的迭代和循环等。注意:typeof(NaN) 和 typeof(Infinity)都返回number 。NaN 参与任何数值计算的结构都是 NaN,而且 NaN != NaN 。Infinity / Infinity = NaN 。string: 面向人类的理性事物,而不是
8、机器信号。人机信息沟通,代码据此理解人的意图等等,都靠它了。简单类型都不是对象,JavaScript 没有将对象化的能力赋予这些简单类型。直接被赋予简单类型常量值的标识符、变量和参数都不是一个对象。所谓“对象化 ”,就是可以将数据和代码组织成复杂结构的能力。JavaScript 中只有 object 类型和 function 类型提供了对象化的能力。没有类object 就是对象的类型。在 JavaScript 中不管多么复杂的数据和代码,都可以组织成 object 形式的对象。但 JavaScript 却没有 “类”的概念!对于许多面向对象的程序员来说,这恐怕是 JavaScript 中最难以
9、理解的地方。是啊,几乎任何讲面向对象的书中,第一个要讲的就是“类” 的概念,这可是面向对象的支柱。这突然没有了“类” ,我们就象一下子没了精神支柱,感到六神无主。看来,要放下对象和类,达到“对象本无根,类型亦无形” 的境界确实是件不容易的事情啊。这样,我们先来看一段 JavaScript 程序:var life = ;for(life.age = 1; life.age 标签将其分成这样的两块:function myfunc ()alert(“hello“);myfunc(); /这里调用 myfunc,输出 hellofunction myfunc ()alert(“yeah“); myfu
10、nc(); /这里调用 myfunc,输出 yeah这时,输出才是各自按顺序来的,也证明了 JavaScript 的确是一段段地执行的。一段代码中的定义式函数语句会优先执行,这似乎有点象静态语言的编译概念。所以,这一特征也被有些人称为:JavaScript 的“预编译”。大多数情况下,我们也没有必要去纠缠这些细节问题。只要你记住一点:JavaScript 里的代码也是一种数据,同样可以被任意赋值和修改的,而它的值就是代码的逻辑。只是,与一般数据不同的是,函数是可以被调用执行的。不过,如果 JavaScript 函数仅仅只有这点道行的话,这与 C+的函数指针,DELPHI 的方法指针,C#的委托
11、相比,又有啥稀奇嘛!然而,JavaScript 函数的神奇之处还体现在另外两个方面:一是函数 function 类型本身也具有对象化的能力,二是函数 function 与对象 object 超然的结合能力。奇妙的对象先来说说函数的对象化能力。任何一个函数都可以为其动态地添加或去除属性,这些属性可以是简单类型,可以是对象,也可以是其他函数。也就是说,函数具有对象的全部特征,你完全可以把函数当对象来用。其实,函数就是对象,只不过比一般的对象多了一个括号“ ()”操作符,这个操作符用来执行函数的逻辑。即,函数本身还可以被调用,一般对象却不可以被调用,除此之外完全相同。请看下面的代码:function
12、 Sing()with(arguments.callee)alert(author + “:“ + poem);Sing.author = “李白“;Sing.poem = “汉家秦地月,流影照明妃。一上玉关道,天涯去不归“;Sing();Sing.author = “李战“;Sing.poem = “日出汉家天,月落阴山前。女儿琵琶怨,已唱三千年“;Sing();在这段代码中,Sing 函数被定义后,又给 Sing 函数动态地增加了author 和 poem 属性。将 author 和 poem 属性设为不同的作者和诗句,在调用 Sing()时就能显示出不同的结果。这个示例用一种诗情画意的方
13、式,让我们理解了 JavaScript 函数就是对象的本质,也感受到了 JavaScript 语言的优美。好了,以上的讲述,我们应该算理解了 function 类型的东西都是和object 类型一样的东西,这种东西被我们称为“ 对象”。我们的确可以这样去看待这些“对象 ”,因为它们既有 “属性”也有“方法” 嘛。但下面的代码又会让我们产生新的疑惑:var anObject = ; /一个对象anObject.aProperty = “Property of object“; /对象的一个属性anObject.aMethod = function()alert(“Method of object
14、“); /对象的一个方法/主要看下面:alert(anObject“aProperty“); /可以将对象当数组以属性名作为下标来访问属性anObject“aMethod“(); /可以将对象当数组以方法名作为下标来调用方法for( var s in anObject) /遍历对象的所有属性和方法进行迭代化处理alert(s + “ is a “ + typeof(anObjects);同样对于 function 类型的对象也是一样:var aFunction = function() ; /一个函数aFunction.aProperty = “Property of function“; /
15、函数的一个属性aFunction.aMethod = function()alert(“Method of function“); /函数的一个方法/主要看下面:alert(aFunction“aProperty“); /可以将函数当数组以属性名作为下标来访问属性aFunction“aMethod“(); /可以将函数当数组以方法名作为下标来调用方法for( var s in aFunction) /遍历函数的所有属性和方法进行迭代化处理alert(s + “ is a “ + typeof(aFunctions);是的,对象和函数可以象数组一样,用属性名或方法名作为下标来访问并处理。那么,它
16、到底应该算是数组呢,还是算对象?我们知道,数组应该算是线性数据结构,线性数据结构一般有一定的规律,适合进行统一的批量迭代操作等,有点像波。而对象是离散数据结构,适合描述分散的和个性化的东西,有点像粒子。因此,我们也可以这样问:JavaScript 里的对象到底是波还是粒子?如果存在对象量子论,那么答案一定是:波粒二象性!因此,JavaScript 里的函数和对象既有对象的特征也有数组的特征。这里的数组被称为“ 字典” ,一种可以任意伸缩的名称值对儿的集合。其实, object和 function 的内部实现就是一个字典结构,但这种字典结构却通过严谨而精巧的语法表现出了丰富的外观。正如量子力学在
17、一些地方用粒子来解释和处理问题,而在另一些地方却用波来解释和处理问题。你也可以在需要的时候,自由选择用对象还是数组来解释和处理问题。只要善于把握 JavaScript 的这些奇妙特性,就可以编写出很多简洁而强大的代码来。放下对象我们再来看看 function 与 object 的超然结合吧。在面向对象的编程世界里,数据与代码的有机结合就构成了对象的概念。自从有了对象,编程世界就被划分成两部分,一个是对象内的世界,一个是对象外的世界。对象天生具有自私的一面,外面的世界未经允许是不可访问对象内部的。对象也有大方的一面,它对外提供属性和方法,也为他人服务。不过,在这里我们要谈到一个有趣的问题,就是“
18、对象的自我意识” 。什么?没听错吧?对象有自我意识?可能对许多程序员来说,这的确是第一次听说。不过,请君看看C+、C#和 Java 的 this,DELPHI 的 self,还有 VB 的 me,或许你会恍然大悟!当然,也可能只是说句“不过如此” 而已。然而,就在对象将世界划分为内外两部分的同时,对象的“自我” 也就随之产生。 “自我意识 ”是生命的最基本特征!正是由于对象这种强大的生命力,才使得编程世界充满无限的生机和活力。但对象的“ 自我意识”在带给我们快乐的同时也带来了痛苦和烦恼。我们给对象赋予了太多欲望,总希望它们能做更多的事情。然而,对象的自私使得它们互相争抢系统资源,对象的自负让对
19、象变得复杂和臃肿,对象的自欺也往往带来挥之不去的错误和异常。我们为什么会有这么多的痛苦和烦恼呢?为此,有一个人,在对象树下,整整想了九九八十一天,终于悟出了生命的痛苦来自于欲望,但究其欲望的根源是来自于自我意识。于是他放下了“自我”,在对象树下成了佛,从此他开始普度众生,传播真经。他的名字就叫释迦摩尼,而JavaScript 真经正是他所传经书中的一本。JavaScript 中也有 this,但这个 this 却与 C+、C# 或 Java 等语言的this 不同。一般编程语言的 this 就是对象自己,而 JavaScript 的 this 却并不一定!this 可能是我,也可能是你,可能是
20、他,反正是我中有你,你中有我,这就不能用原来的那个“ 自我 ”来理解 JavaScript 这个 this 的含义了。为此,我们必须首先放下原来对象的那个“自我” 。我们来看下面的代码:function WhoAmI() /定义一个函数 WhoAmIalert(“Im “ + this.name + “ of “ + typeof(this);WhoAmI(); /此时是 this 当前这段代码的全局对象,在浏览器中就是window 对象,其 name 属性为空字符串。输出: Im of objectvar BillGates = name: “Bill Gates“;BillGates.Wh
21、oAmI = WhoAmI; /将函数 WhoAmI 作为 BillGates的方法。BillGates.WhoAmI(); /此时的 this 是 BillGates。输出:Im Bill Gates of objectvar SteveJobs = name: “Steve Jobs“;SteveJobs.WhoAmI = WhoAmI; /将函数 WhoAmI 作为SteveJobs 的方法。SteveJobs.WhoAmI(); /此时的 this 是 SteveJobs。输出:Im Steve Jobs of objectWhoAmI.call(BillGates); /直接将 Bi
22、llGates 作为 this,调用WhoAmI。输出:Im Bill Gates of objectWhoAmI.call(SteveJobs); /直接将 SteveJobs 作为 this,调用WhoAmI。输出:Im Steve Jobs of objectBillGates.WhoAmI.call(SteveJobs); /将 SteveJobs 作为 this,却调用 BillGates 的 WhoAmI 方法。输出:Im Steve Jobs of objectSteveJobs.WhoAmI.call(BillGates); /将 BillGates 作为 this,却调用 S
23、teveJobs 的 WhoAmI 方法。输出:Im Bill Gates of objectWhoAmI.WhoAmI = WhoAmI; /将 WhoAmI 函数设置为自身的方法。WhoAmI.name = “WhoAmI“;WhoAmI.WhoAmI(); /此时的 this 是 WhoAmI 函数自己。输出:Im WhoAmI of function(name: “nobody“, WhoAmI: WhoAmI).WhoAmI(); /临时创建一个匿名对象并设置属性后调用 WhoAmI 方法。输出:Im nobody of object从上面的代码可以看出,同一个函数可以从不同的角度来
24、调用,this 并不一定是函数本身所属的对象。this 只是在任意对象和 function 元素结合时的一个概念,是种结合比起一般对象语言的默认结合更加灵活,显得更加超然和洒脱。在 JavaScript 函数中,你只能把 this 看成当前要服务的“ 这个”对象。this 是一个特殊的内置参数,根据 this 参数,您可以访问到“这个”对象的属性和方法,但却不能给 this 参数赋值。在一般对象语言中,方法体代码中的 this可以省略的,成员默认都首先是“自己” 的。但 JavaScript 却不同,由于不存在“自我”,当访问“这个”对象时,this 不可省略!JavaScript 提供了传递
25、 this 参数的多种形式和手段,其中,象BillGates.WhoAmI()和 SteveJobs.WhoAmI()这种形式,是传递 this 参数最正规的形式,此时的 this 就是函数所属的对象本身。而大多数情况下,我们也几乎很少去采用那些借花仙佛的调用形式。但只我们要明白 JavaScript 的这个“自我”与其他编程语言的 “自我”是不同的,这是一个放下了的 “自我”,这就是 JavaScript 特有的世界观。对象素描已经说了许多了许多话题了,但有一个很基本的问题我们忘了讨论,那就是:怎样建立对象?在前面的示例中,我们已经涉及到了对象的建立了。我们使用了一种被称为 JavaScri
26、pt Object Notation(缩写 JSON)的形式,翻译为中文就是“JavaScript 对象表示法”。JSON 为创建对象提供了非常简单的方法。例如,创建一个没有任何属性的对象:var o = ;创建一个对象并设置属性及初始值:var person = name: “Angel“, age: 18, married: false;创建一个对象并设置属性和方法:var speaker = text: “Hello World“, say: function()alert(this.text);创建一个更复杂的对象,嵌套其他对象和对象数组等:var company =name: “Mi
27、crosoft“,product: “softwares“,chairman: name: “Bill Gates“, age: 53, Married: true,employees: name: “Angel“, age: 26, Married: false, name: “Hanson“, age: 32, Marred: true,readme: function() document.write(this.name + “ product “ + this.product);JSON 的形式就是用大括“”号包括起来的项目列表,每一个项目间并用逗号“,” 分隔,而项目就是用冒号“:”
28、 分隔的属性名和属性值。这是典型的字典表示形式,也再次表明了 JavaScript 里的对象就是字典结构。不管多么复杂的对象,都可以被一句 JSON 代码来创建并赋值。其实,JSON 就是 JavaScript 对象最好的序列化形式,它比 XML 更简洁也更省空间。对象可以作为一个 JSON 形式的字符串,在网络间自由传递和交换信息。而当需要将这个 JSON 字符串变成一个 JavaScript 对象时,只需要使用 eval 函数这个强大的数码转换引擎,就立即能得到一个 JavaScript 内存对象。正是由于 JSON 的这种简单朴素的天生丽质,才使得她在 AJAX 舞台上成为璀璨夺目的明星
29、。JavaScript 就是这样,把面向对象那些看似复杂的东西,用及其简洁的形式表达出来。卸下对象浮华的浓妆,还对象一个眉目清晰!构造对象好了,接下我们来讨论一下对象的另一种创建方法。除 JSON 外,在 JavaScript 中我们可以使用 new 操作符结合一个函数的形式来创建对象。例如:function MyFunc() ; /定义一个空函数var anObj = new MyFunc(); /使用 new 操作符,借助 MyFun 函数,就创建了一个对象JavaScript 的这种创建对象的方式可真有意思,如何去理解这种写法呢?其实,可以把上面的代码改写成这种等价形式:function
30、 MyFunc();var anObj = ; /创建一个对象MyFunc.call(anObj); /将 anObj 对象作为 this 指针调用 MyFunc 函数我们就可以这样理解,JavaScript 先用 new 操作符创建了一个对象,紧接着就将这个对象作为 this 参数调用了后面的函数。其实,JavaScript 内部就是这么做的,而且任何函数都可以被这样调用!但从 “anObj = new MyFunc()” 这种形式,我们又看到一个熟悉的身影,C+ 和 C#不就是这样创建对象的吗?原来,条条大路通灵山,殊途同归啊!君看到此处也许会想,我们为什么不可以把这个 MyFunc 当作
31、构造函数呢?恭喜你,答对了!JavaScript 也是这么想的!请看下面的代码:1 function Person(name) /带参数的构造函数2 3 this.name = name; /将参数值赋给给 this 对象的属性4 this.SayHello = function() alert(“Hello, Im “ + this.name); /给 this 对象定义一个 SayHello 方法。5 ;67 function Employee(name, salary) /子构造函数8 9 Person.call(this, name); /将 this 传给父构造函数10 this.s
32、alary = salary; /设置一个 this 的 salary 属性11 this.ShowMeTheMoney = function() alert(this.name + “ $“ + this.salary); /添加 ShowMeTheMoney 方法。12 ;13 14 var BillGates = new Person(“Bill Gates“); /用 Person 构造函数创建 BillGates 对象15 var SteveJobs = new Employee(“Steve Jobs“, 1234); /用Empolyee 构造函数创建 SteveJobs 对象1
33、617 BillGates.SayHello(); /显示:Im Bill Gates18 SteveJobs.SayHello(); /显示:Im Steve Jobs19 SteveJobs.ShowMeTheMoney(); /显示:Steve Jobs $12342021 alert(BillGates.constructor = Person); /显示:true22 alert(SteveJobs.constructor = Employee); /显示:true23 24 alert(BillGates.SayHello = SteveJobs.SayHello); /显示:fa
34、lse这段代码表明,函数不但可以当作构造函数,而且还可以带参数,还可以为对象添加成员和方法。其中的第9行,Employee 构造函数又将自己接收的this 作为参数调用 Person 构造函数,这就是相当于调用基类的构造函数。第21、22行还表明这样一个意思: BillGates 是由 Person 构造的,而SteveJobs 是由 Employee 构造的。对象内置的 constructor 属性还指明了构造对象所用的具体函数!其实,如果你愿意把函数当作“类” 的话,她就是 “类”,因为她本来就有“ 类”的那些特征。难道不是吗?她生出的儿子各个都有相同的特征,而且构造函数也与类同名嘛!但要
35、注意的是,用构造函数操作 this 对象创建出来的每一个对象,不但具有各自的成员数据,而且还具有各自的方法数据。换句话说,方法的代码体(体现函数逻辑的数据)在每一个对象中都存在一个副本。尽管每一个代码副本的逻辑是相同的,但对象们确实是各自保存了一份代码体。上例中的最后一句说明了这一实事,这也解释了 JavaScript 中的函数就是对象的概念。同一类的对象各自有一份方法代码显然是一种浪费。在传统的对象语言中,方法函数并不象 JavaScript 那样是个对象概念。即使也有象函数指针、方法指针或委托那样的变化形式,但其实质也是对同一份代码的引用。一般的对象语言很难遇到这种情况。不过,JavaSc
36、ript 语言有大的灵活性。我们可以先定义一份唯一的方法函数体,并在构造 this 对象时使用这唯一的函数对象作为其方法,就能共享方法逻辑。例如:function SayHello() /先定义一份 SayHello 函数代码alert(“Hello, Im “ + this.name);function Person(name) /带参数的构造函数this.name = name; /将参数值赋给给 this 对象的属性this.SayHello = SayHello; /给 this 对象 SayHello 方法赋值为前面那份 SayHello 代码。;var BillGates = ne
37、w Person(“Bill Gates“); /创建 BillGates 对象var SteveJobs = new Person(“Steve Jobs“); /创建 SteveJobs对象alert(BillGates.SayHello = SteveJobs.SayHello); /显示:true其中,最后一行的输出结果表明两个对象确实共享了一个函数对象。虽然,这段程序达到了共享了一份方法代码的目的,但却不怎么优雅。因为,定义SayHello 方法时反映不出其与 Person 类的关系。 “优雅” 这个词用来形容代码,也不知道是谁先提出来的。不过,这个词反映了程序员已经从追求代码的正确
38、、高效、可靠和易读等基础上,向着追求代码的美观感觉和艺术境界的层次发展,程序人生又多了些浪漫色彩。显然,JavaScript 早想到了这一问题,她的设计者们为此提供了一个有趣的 prototype 概念。初看原型prototype 源自法语,软件界的标准翻译为 “原型”,代表事物的初始形态,也含有模型和样板的意义。JavaScript 中的 prototype 概念恰如其分地反映了这个词的内含,我们不能将其理解为 C+的 prototype 那种预先声明的概念。JavaScript 的所有 function 类型的对象都有一个 prototype 属性。这个prototype 属性本身又是一个
39、 object 类型的对象,因此我们也可以给这个prototype 对象添加任意的属性和方法。既然 prototype 是对象的“原型”,那么由该函数构造出来的对象应该都会具有这个“原型” 的特性。事实上,在构造函数的 prototype 上定义的所有属性和方法,都是可以通过其构造的对象直接访问和调用的。也可以这么说,prototype 提供了一群同类对象共享属性和方法的机制。我们先来看看下面的代码:function Person(name)this.name = name; /设置对象属性,每个对象各自一份属性数据;Person.prototype.SayHello = function()
40、 /给 Person 函数的prototype 添加 SayHello 方法。alert(“Hello, Im “ + 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(
41、BillGates.SayHello = SteveJobs.SayHello); /因为两个对象是共享 prototype 的 SayHello,所以显示:true程序运行的结果表明,构造函数的 prototype 上定义的方法确实可以通过对象直接调用到,而且代码是共享的。显然,把方法设置到 prototype 的写法显得优雅多了,尽管调用形式没有变,但逻辑上却体现了方法与类的关系,相对前面的写法,更容易理解和组织代码。那么,对于多层次类型的构造函数情况又如何呢?我们再来看下面的代码:1 function Person(name) /基类构造函数2 3 this.name = name;4
42、;5 6 Person.prototype.SayHello = function() /给基类构造函数的prototype 添加方法7 8 alert(“Hello, Im “ + 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.
43、prototype.ShowMeTheMoney = function() /给子类添构造函数的 prototype 添加方法20 21 alert(this.name + “ $“ + this.salary);22 ;2324 var BillGates = new Person(“Bill Gates“); /创建基类 Person的 BillGates 对象25 var SteveJobs = new Employee(“Steve Jobs“, 1234); /创建子类 Employee 的 SteveJobs 对象2627 BillGates.SayHello(); /通过对象直接
44、调用到 prototype 的方法28 SteveJobs.SayHello(); /通过子类对象直接调用基类prototype 的方法,关注!29 SteveJobs.ShowMeTheMoney(); /通过子类对象直接调用子类prototype 的方法3031 alert(BillGates.SayHello = SteveJobs.SayHello); /显示:true,表明 prototype 的方法是共享的这段代码的第17行,构造了一个基类的对象,并将其设为子类构造函数的prototype,这是很有意思的。这样做的目的就是为了第28行,通过子类对象也可以直接调用基类 prototy
45、pe 的方法。为什么可以这样呢?原来,在 JavaScript 中,prototype 不但能让对象共享自己财富,而且prototype 还有寻根问祖的天性,从而使得先辈们的遗产可以代代相传。当从一个对象那里读取属性或调用方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的 prototype 对象那里寻找;如果 prototype 没有,又会去 prototype 自己关联的前辈 prototype 那里寻找,直到找到或追溯过程结束为止。在 JavaScript 内部,对象的属性和方法追溯机制是通过所谓的prototype 链来实现的。当用 new 操作符构造对象时,也会同时将构造
46、函数的 prototype 对象指派给新创建的对象,成为该对象内置的原型对象。对象内置的原型对象应该是对外不可见的,尽管有些浏览器(如 Firefox)可以让我们访问这个内置原型对象,但并不建议这样做。内置的原型对象本身也是对象,也有自己关联的原型对象,这样就形成了所谓的原型链。在原型链的最末端,就是 Object 构造函数 prototype 属性指向的那一个原型对象。这个原型对象是所有对象的最老祖先,这个老祖宗实现了诸如toString 等所有对象天生就该具有的方法。其他内置构造函数,如 Function, Boolean, String, Date 和 RegExp 等的 prototy
47、pe 都是从这个老祖宗传承下来的,但他们各自又定义了自身的属性和方法,从而他们的子孙就表现出各自宗族的那些特征。这不就是“ 继承” 吗?是的,这就是 “继承”,是 JavaScript 特有的“原型继承”。“原型继承 ”是慈祥而又严厉的。原形对象将自己的属性和方法无私地贡献给孩子们使用,也并不强迫孩子们必须遵从,允许一些顽皮孩子按自己的兴趣和爱好独立行事。从这点上看,原型对象是一位慈祥的母亲。然而,任何一个孩子虽然可以我行我素,但却不能动原型对象既有的财产,因为那可能会影响到其他孩子的利益。从这一点上看,原型对象又象一位严厉的父亲。我们来看看下面的代码就可以理解这个意思了:function P
48、erson(name)this.name = name;Ppany = “Microsoft“; /原型的属性Person.prototype.SayHello = function() /原型的方法alert(“Hello, Im “ + this.name + “ of “ + pany);var BillGates = new Person(“Bill Gates“);BillGates.SayHello(); /由于继承了原型的东西,规规矩矩输出:Hello, Im Bill Gatesvar SteveJobs = new Person(“Steve Jobs“);SteveJpany = “Apple“; /设置自己的 company 属性,掩盖了原型的 company 属性SteveJobs.SayHello = function() /实现了自己的 SayHello 方法,掩盖了原型的 SayHello 方法alert(“Hi