最近较为关注JavaScript,主要原因是对动态语言,及动态语言的实现比较感兴趣.无奈我本是C++起家,静态类型观念已根深蒂固,让我一下子接受"动态",还真有些适应不过来.也许是当时对C++对象模型的热爱,我首先想到了从对象模型上来看JavaScript,希望让自己胸中自有丘壑.无意中在网上看到了
http://developer.mozilla.org/中有一篇文章正合我意.正好晚上部门一起吃饭去,下午也没有什么工作,翻译出来和大家共享.
JavaScript核心参考——对象模型的细节
基于类的语言VS.基于原型的语言(Class-Based VS. Prototype-Based Language)
基于类的面向对象的语言,诸如Java和C++。它们是建立在两个概念上并不相同的实体(entity)上:类(classed)和实例(instances)。
- 一个类定义了所有的属性(在Java中的方法和字段,以及C++中的成员,都可被看作是属性)。这些属性描述了一组特定对象(译注:也就是该类的实例)的特征。类是一个抽象的概念,而不是它所描述的一组对象(即该类实例)的任何特定成员。例如,一个Employee类用来代表该组所有的employee对象.
- 另一个概念,实例(instance)。是一个类(class)的实体(instantiation);也就是class所代表的一组成员中的一个。举个例子Victoria可以是Employee类的一个实例,表示一个特定的员工的个体。一个实例和生成这个实例的类有着同样(一个不多,一个不少)的属性。
基于原型的语言,比如JavaScript就没有这样的区别。它仅仅有一个对象概念,而没有似于C++中的类和实例的概念。对象作为一个模型(template)来使用,通过该模型可以模塑出一个新对象的初始属性(译注:因为该新对象的属性后期还可以被更改,所以此处称之为最初属性)。不管是在创建对象的时候,还是运行时(runtime),任何一个对象都可以指定自己的属性。(译注:有别于像C++中必须通过在定义时修改生成该对象的类,来修改该对象的属性) 除此之外,任何一个对象本身可以作为其它对象的一个原形(Prototype),从而关联到其它对象中,并且允许其它对象共享该对象的属性。
定义一个类(Defining a class)
在基于类(class-based)的语言中,你可以单独地定义一个类。在那里你可以指定一个特别的方法,该方法被称为构造函数(Constructor),用来创建该类的实例。构造函数可以在创建一个实例时指定该实例的初始值,或是执行其它必要地处理。你可以用new操作符来调用构造函数并创建一个类的实例。
JavaScript定义类的过程与其类似,但是JavaScript不会将类型的定义从构造函数中分离出来。相反的,你可以定义一个构造函数,并以一组特定的初始化属性和值(记住,在运行时这些属性和值都是可以更改的)来创建一个对象。在JavaScript中任何函数都可以作为构造函数。同样地你仍旧可以使用new操作符通过构造函数创建一个新的对象。
子类和继承(Subclassed and Inheritance)
在基于类(class-based)的语言中,你可以通过类的定义来创建类层次(父类,子类等)。在类的定义中,你可以指定该类是已存在的一个类的子类。子类(subclass)可以继承父类(superclass)所有的属性。除此而外,还可以新增自己属性或是修改继承来的属性。举个例子,假设Employee类只有两个属性:name和dept。同时Manager类是Employee类的一个子类,并新增了一个report属性。这样的话,Manager类的一个实例将会有三个属性,分别是:name,dept和report.
JavaScript以另外一种方式实现继承,你可以为一个构造函数关联原型对象(prototypical object)来实现继承。同样地,你也可以创建和上面的Employee-Manager示例,之不过用了一些不同的术语(terminology).首先,你定义一个Employee的构造函数,并指定name和dept属性。接下来,你再定义Manager属性,并指定report属性。最后,你再指定一个新的Employee对象,作为Manager构造函数的原型(prototype)。再此之后,你若创建一个新的Manager对象(通过new操作符),它便会从Employee对象继承name和dept属性。
添加和移除属性(Adding and Removing Properties)
在基于类(class-based)的语言中,一般你在编译时(compile-time)创建一个类。之后你可能在编译时实例化该类(译注:比如C++中的模板类的实例化),也可能是在运行时(run-time)实例化该类。在你定义完一个类之后,你不能再修改该类的属性的数目和类型。然而,在JavaScript中,你可以在运行时添加或移除任何对象的属性。你在给一个对象添加一个属性时,添加的属性是作为一组对象的原型。这一组对象从这个原型中一样可以获得新的属性。(原文为:If you add a property to an object that is used as the prototype for a set of objects, the objects for which it is the prototype also get the new property. )
不同点的总结(Summary of Difference)
下面的表格对一些不同点作了简单地总结。在本章的剩余部分,将会详细地描述在JavaScript中怎么样使用构造函数和原型来创建一个类的继承体系(hierarchy),同时将JavaScript中创建类继承体系的方法和Java中创建同样的类继承体系的方法进行比较。
Class-based (Java) |
Prototype-based (JavaScript) |
类和实例是两个不同的实体 |
所有的对象都是实例 |
以"类型定义"方式来申明一个类;以构造函数来实例化一个类。 |
以构造函数来定义和创建一组对象 |
用new操作符来创建单个对象 |
相同 |
在"类型定义"中定义一个类是现存的类的子类,以此来构建一个继承体系 |
将一个对象作为一个原型关联至构造函数,以此来构建一个继承体系 |
继承类型链(class-chain)中的属性 |
继承原型链(prototype-chain)中的属性 |
"类型定义"指定了该类任何一个实例的所有属性 |
构建函数或原型指定一组初始化的属性.可以动态地为单个对象或是一组对象添加或是移除属性 |
Jerry.Chou
2/1'08
阅读(1306) | 评论(0) | 转发(0) |