by Mike Koss
March 26th, 2003
这是一篇,我个人认为最好的,Javascript面向对象编程的文章。翻译不好的地方,还望大家指正,谢谢。
如果您需要,可以访问下面的地址取得原文:
http://mckoss.com/jscript/object.htm在我的blog里,将会陆续推出这个理论的实践、源码。
介绍
大部分的Javascript的编写者,都只是把它做为简单的脚本引擎,来创建动态的Web页面。同时Web设计人员开始使用在IE浏览器中定义的对象模型,来处理Web页面的内容。但是大多数的开发者并没有认识到Javascript在其自身就具有强大的面向对象的功能。当不使用强类型的时候(变量不必先声明后使用),这种解析性的语言,可以巧妙的达成面向对象(object-oriented)的功能,包括:
- 封装(Encapsulation)
- 多台(Polymorphism )
- 继承(Inheritance)
虽然,通过一系列的范例(对于好奇的读者,这些范例片断代码是很生动的),我将会阐述对象在Javascript中,对象是如何被使用,并且如何实现面向对象的。
简单对象(Simple Objects)
在Javascript中,最简单的可构建的对象,就是机制内建的Object对象。在Javascript中,对象是指定名称的属性(property)的集合。做为解析性语言,Javascript允许给一个对象创建任意个属性,在任何时间(不像C++,它的属性是可以在任何时间添加给对象。它们并不需要事先在对象的声明(definition)或者构造(constructor)中,进行定义)。
所以,举例来说,我们可以创建一个对象,然后添加一系列的属性给它,就像这样:
<listing style="FONT-SIZE: 14px">obj = new Object;<br><br>obj.x = 1;<br><br>obj.y = 2;</listing>
这里,Javascript对象,可以用图形表示成这样的结构:
obj |
x |
1 |
y |
2 |
prototype properties |
constructor |
functionObject |
另外需要注意的是,我们创建的x和y属性, 我们的对象默认有一个属性constructor t他指向一个Javascript内部对象函数(funciton)。 (译者注:prototype,原型在后文会有进一步的说明)
对象的构造函数(Object Constructors)
对于要定义的对象类型,Javascript允许我们自己给对象类型定义构造函数:
<listing style="FONT-SIZE: 14px">function Foo()<br><br>{<br><br> this.x = 1;<br><br> this.y = 2;<br><br>}<br><br><br><br>obj1 = new Foo;<br><br></listing>
obj1 |
x |
1 |
y |
2 |
prototype properties |
constructor |
functionFoo |
这里要说明的是,我们可以创建任意多个Foo类型的对象实例,它们也都将分别初始化自己的x和y属性为1和2。
简单的方法的的实现(A Simple Method Implementation)
为了封装对象的行为功能,向调用者隐藏执行过程,我们需要给对象创建方法(method)。Javascript允许你将任意一个函数(function)分配给对象的一个属性。当我们使用 obj.Function 的语法调用函数的时候,将把函数原来定义this 的指向,当前这个对象(就像它在构造函数中的那样)。
<listing style="FONT-SIZE: 14px">function Foo()<br><br>{<br><br> this.x = 1;<br><br> this.y = 2;<br><br> this.Bar = MyMethod;<br><br>}<br><br><br><br>function MyMethod(z)<br><br>{<br><br> this.x += z;<br><br>}<br><br><br><br>obj2 = new Foo;<br><br></listing>
obj2 |
x |
1 |
y |
2 |
Bar |
functionMyMethod |
prototype properties |
constructor |
functionFoo |
现在,我们简单的调用一下,做为对象的方法的Bar函数:
<listing style="FONT-SIZE: 14px">obj2.Bar(3);<br><br></listing>
obj2 |
x |
4 |
y |
2 |
Bar |
functionMyMethod |
prototype properties |
constructor |
functionFoo |
所以,你可以方便的给对象定义构造函数和方法,使其对调用者而言,隐藏它的实现过程。同样的,因为,Javascript不是强类型的,所以,我们可以通过定义有相同名字的方法的对象,来简单的实现多台性(polymorphism)。
<listing style="FONT-SIZE: 14px">function Foo()<br><br>{<br><br> this.x = 1;<br><br> this.DoIt = FooMethod;<br><br>}<br><br><br><br>function FooMethod()<br><br>{<br><br> this.x++;<br><br>}<br><br><br><br>function Bar()<br><br>{<br><br> this.z = 'Hello';<br><br> this.DoIt = BarMethod;<br><br>}<br><br><br><br>function BarMethod()<br><br>{<br><br> this.z += this.z;<br><br>}<br><br><br><br>obj1 = new Foo;<br><br>obj2 = new Bar;<br><br></listing>
obj1 |
x |
1 |
DoIt |
functionFooMethod |
prototype properties |
constructor |
functionFoo |
obj2 |
z |
Hello |
DoIt |
functionBarMethod |
prototype properties |
constructor |
functionBar |
<listing style="FONT-SIZE: 14px">function Poly(obj)<br><br>{<br><br> obj.DoIt();<br><br>}<br><br><br><br>Poly(obj1);<br><br>Poly(obj2);<br><br></listing>
obj1 |
x |
2 |
DoIt |
functionFooMethod |
prototype properties |
constructor |
functionFoo |
obj2 |
z |
HelloHello |
DoIt |
functionBarMethod |
prototype properties |
constructor |
functionBar |
使用原型实现方法(Using Prototypes to Implement Methods)
试想一下,这使很笨的办法,每次我们都要创建名称没有使用意义的方法函数,然后在构造函数里,把它们分配给每个方法属性。其实,我发现使用Javascript的原型(prototype)机制,是更为直接的方法。
每个对象,可以参照一个原型对象,原型对象包含有自己的属性。它就好比是一个对象定义的备份。当代码,引用一个属性的时候,它并不存在于对象本身里,那么Javascript将会自动的在原型的定义中查找这个属性。而且,事实上,一个对象的原型对象又可以参照另外一个原型对象,就这样以链式最终关联到基类对象的构造函数。(译者注:对于DOM对象等系统的对象,原型对象可以修改,但是不可以赋值改变的,只有自定义对象可以。)这是template模型(译者注:模板方法,《设计模式》中行为模式的一种),它可以简化我们对方法的定义,同时也可以产生强大的继承机制。
在Javascript中,原型对象是被分配给构造函数的。所以,为了修改对象的原型,必须首先修改构造函数的原型对象的成员。然后,当对象从构造函数被构造的时候,对象将会引用到构造函数的原型。
<listing style="FONT-SIZE: 14px">function Foo()<br><br>{<br><br> this.x = 1;<br><br>}<br><br><br><br>Foo.prototype.y = 2;<br><br>obj = new Foo;<br><br>document.write('obj.y = ' + obj.y);<br><br></listing>obj.y = 2
obj |
x |
1 |
prototype properties |
constructor |
functionFoo
|
y |
2 |
即使我们并没有直接的把y属性分配给obj,obj对象仍然有一个y属性。当我们引用obj.y的时候,Javascript实际返回obj.constructor.prototype.y的引用。我们可以肯定的是,原型的值的改变,也将会反映到对象中。
<listing style="FONT-SIZE: 14px">Foo.prototype.y = 3;<br><br>document.write('obj.y = ' + obj.y);<br><br></listing>obj.y = 3
obj |
x |
1 |
prototype properties |
constructor |
functionFoo
|
y |
3 |
我们也可以发现,一旦我们初始化一个属性的“私有”(
private )的值,存放在原型中的值并不会收到影响:
<listing style="FONT-SIZE: 14px">obj.y = 4;<br><br>Foo.prototype.y = 3;<br><br></listing>
obj |
x |
1 |
y |
4 |
prototype properties |
constructor |
functionFoo
|
原型方法的命名(Prototype Method Naming)
我发现了可以直接定义类的原型的方法的语句,而不需要单独的函数的名称:
<listing style="FONT-SIZE: 14px">function Foo()<br><br>{<br><br> this.x = 1;<br><br>}<br><br><br><br>function Foo.prototype.DoIt()<br><br>{<br><br> this.x++;<br><br>}<br><br>obj = new Foo;<br><br>obj.DoIt();</listing>
obj |
x |
2 |
prototype properties |
constructor |
functionFoo
prototype |
DoIt |
functionFoo.prototype.DoIt |
|
DoIt |
functionFoo.prototype.DoIt |
基于原型的子类继承(Prototype-based Subclassing )
一旦可以建立原型对象链,我们就可以使用它做为对象的子类的类型。这个方法要注意的是,我们创建了一个基类对象的实例,并把它做为我们的类的构造函数的原型对象。这么做,我们所创建的所有的对象,将继承基类对象的所有成员和(方法)。但是要注意,基类的构造函数只会被调用一次(译者注:从基类到子类的构造函数都是唯一的,即基类的构造函数)。这不像C++,基类的构造函数,对于每个继承的子类,都可以分别的调用。在后面,我将展示,当独立的构造函数被需要的时候,另外一种可选的方式来创建继承类。
<listing style="FONT-SIZE: 14px">function TextObject(st)<br><br>{<br><br> this.st = st;<br><br> this.fVisible = true;<br><br>}<br><br><br><br>function TextObject.prototype.Write()<br><br>{<br><br> document.write('<br><br>' + this.st);<br><br>}<br><br><br><br>function ItalicTextObject(st)<br><br>{<br><br> this.st = st;<br><br>}<br><br><br><br>ItalicTextObject.prototype = new TextObject('x');<br><br><br><br>ItalicTextObject.prototype.Write = ITOWrite;<br><br>function ITOWrite()<br><br>{<br><br> document.write('<br><br><em>' + this.st + '</em>');<br><br>}<br><br><br><br>obj1 = new TextObject('Hello, mom');<br><br>obj2 = new ItalicTextObject('Hello, world');<br><br>obj1.Write();<br><br>obj2.Write();<br><br></listing>
Hello, mom
Hello, world
obj1 |
st |
Hello,mom |
fVisible |
true |
prototype properties |
constructor |
functionTextObject
prototype |
Write |
functionTextObject.prototype.Write |
|
Write |
functionTextObject.prototype.Write |
obj2 |
st |
Hello,world |
prototype properties |
constructor |
functionTextObject
prototype |
Write |
functionTextObject.prototype.Write |
|
fVisible |
true |
Write |
functionITOWrite |
这个结构存在两个问题。一个是,当每次构造继承的类的时候,基类的构造函数都不会被调用。假如,构造函数不做太多的事情,只是初始化一些成员变量为静态的值,这个问题就不是太明显了。第二个,注意,我将不能使用"function Obj.prototype.Method"的方式,来定义继承类的成员。这是因为,对于构造函数来说,我要把这些方法的定义,放入新创建的原型对象,而不是添加到,默认的原型对象。
另一种子类继承方式(An Alternate Subclassing Paradigm)
我们可以提出一种方法,更类似于反映C++类的概念和子类的定义,以及从子类反向存取基类的纯原型链的风格。它需要添加新的方法DeriveFrom给基类。
<listing style="FONT-SIZE: 14px">function Function.prototype.DeriveFrom(fnBase)<br><br><br><br>{<br><br><br><br> var prop;<br><br><br><br><br><br><br><br> if (this == fnBase)<br><br><br><br> {<br><br><br><br> alert("Error - cannot derive from self");<br><br><br><br> return;<br><br><br><br> }<br><br><br><br><br><br><br><br> for (prop in fnBase.prototype)<br><br><br><br> {<br><br><br><br> if (typeof(fnBase.prototype[prop]) == "function" && !this.prototype[prop])<br><br><br><br> {<br><br><br><br> this.prototype[prop] = fnBase.prototype[prop];<br><br><br><br> }<br><br><br><br> }<br><br><br><br><br><br><br><br> this.prototype[fnBase.StName()] = fnBase;<br><br><br><br>}</listing><listing style="FONT-SIZE: 14px">function Function.prototype.StName()<br><br><br><br>{<br><br><br><br> var st;<br><br><br><br><br><br><br><br> st = this.toString();<br><br><br><br> st = st.substring(st.indexOf(" ")+1, st.indexOf("("))<br><br><br><br><br><br><br><br> return st;<br><br><br><br>}</listing><listing style="FONT-SIZE: 14px">function TextObject(st)<br><br>{<br><br> this.st = st;<br><br> this.fVisible = true;<br><br>}<br><br><br><br>function TextObject.prototype.Write()<br><br>{<br><br> document.write('<br><br>' + this.st);<br><br>}<br><br><br><br>function TextObject.prototype.IsVisible()<br><br>{<br><br> return this.fVisible;<br><br>}<br><br><br><br>function ItalicTextObject(st)<br><br>{<br><br> this.TextObject(st);<br><br>}<br><br><br><br>ItalicTextObject.DeriveFrom(TextObject);<br><br><br><br>function ItalicTextObject.prototype.Write()<br><br>{<br><br> document.write('<br><br><em>' + this.st + '</em>');<br><br>}<br><br><br><br>obj1 = new TextObject('Hello, mom');<br><br>obj2 = new ItalicTextObject('Hello, world');<br><br>obj1.Write();<br><br>obj2.Write();<br><br></listing>
Hello, mom
Hello, world
obj1 |
st |
Hello,mom |
fVisible |
true |
prototype properties |
constructor |
functionTextObject
prototype |
Write |
functionTextObject.prototype.Write |
IsVisible |
functionTextObject.prototype.IsVisible |
|
IsVisible |
functionTextObject.prototype.IsVisible |
Write |
functionTextObject.prototype.Write |
obj2 |
st |
Hello,world |
fVisible |
true |
prototype properties |
constructor |
functionItalicTextObject
prototype |
Write |
functionItalicTextObject.prototype.Write |
IsVisible |
functionTextObject.prototype.IsVisible |
TextObject |
functionTextObject
prototype |
Write |
functionTextObject.prototype.Write |
IsVisible |
functionTextObject.prototype.IsVisible |
|
|
IsVisible |
functionTextObject.prototype.IsVisible |
TextObject |
functionTextObject
prototype |
Write |
functionTextObject.prototype.Write |
IsVisible |
functionTextObject.prototype.IsVisible |
|
Write |
functionItalicTextObject.prototype.Write |
我们还得到了一个额外的好处,那就是,我们可以从多个基类进行继承(多重的继承)。
分享到:
相关推荐
《JavaScript面向对象编程指南》内容包括:JavaScript作为一门浏览器语言的..., 《JavaScript面向对象编程指南》着重介绍JavaScript在面向对象方面的特性,展示如何构建强健的、可维护的、功能强大的应用程序及程序库。
JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在... 《JavaScript面向对象编程指南》着重介绍JavaScript在面向对象方面的特性,展示如何构建强健的、可维护的、功能强大的应用程序及程序库
面向对象编程的基础知识及其在JavaScript中的运用;数据类型、操作符以及流程控制语句;函数、闭包、对象和原型等概念,以代码重用为目的的继承模式;BOM、DOM、浏览器事件、AJAX和JSON;如何实现JavaScript中缺失的...
NULL 博文链接:https://goyourauntie.iteye.com/blog/1179204
Javascript 中的面向对象编程
JavaScript面向对象编程.pdf
JavaScript面向对象编程指南是完整的扫描版...
JavaScript学习深入—面向对象编程,很不错的一本书。
JavaScript面向对象编程指南 pdf,学习JavaScript实用,难得。
javascript面向对象编程指南 2nd英文版,英文名:Object-Oriented JavaScript。 What you will learn from this book The basics of object-oriented programming, and how to apply it in the JavaScript ...
资源名称:JavaScript面向对象编程指南(第2版)内容简介:1.本书是唯一一本介绍Javascript面向对象编程的图书。2.本书作者是知名的Web开发人员和作者。受到国内众多前端开发人员,如淘宝UED团队的推崇和推荐...
JavaScript面向对象编程指南完整版是扫描的....