“面向对象”有三种基本特性,即封装、继承和多态。一般来说,三个特性都完全满足的话,我们称之为“面向对象语言”,而称满足部分特性的语言为“基于对象语言”。
“对象系统”的继承特性,有三种实现方案,包括基于类、基于原型和基于原类。而javascript中没有采用我们常用的类继承体系,而是使用原型继承来实现对象系统。因此javascript中没有类,而采用一种名为“构造器”的机制来实现类的某些功用。
关于这个话题我想从空对象与空的对象来开始讨论原型继承,空对象(null)我们要先明确它的定义它是一个保留字,属于对象类型而且对象是空值,null对象可以参与运算,但因为他没有属性也没有方法,同时也没有原型,所以相关的调用都会失败。由于它并不是object()构造器实例而来,因此instanceof()运算会返回false。而所谓空的对象,就是一个标准的、通过object()构造的对象实例,例如obj=new object();空的对象有对象的一切属性。
下面我们来讨论一下原型继承的基本属性,在javascript对象系统的实现来讲,对象并没有原型,而构造器有原型,对象只有“构造自某个原型”的问题,并不存在“持有某个原型”的问题。原型其实也是一个对象实例。原型的含义是指:如果构造器有一个原型对象A,则由该构造器创建的实例都必然复制自A,而且我们还要明确一个概念就是空对象是所有对象的基础,我们用下面的代码来考察一下最基本的object()构造器:
//取原型对象
pro =Object.prototype;
//列举对象成员并计数
var num=0;
for(var n in pro){
num++;
}
//显示计数:0
alert(num);
可见,object()构造器的原型就是一个空对象。那么这有什么意义呢,这意味这
obj1=new Object();
obj2={};
无非是从object.prototype上复制出一个“对象”的映像,但这种方法每复制出一个实例,新的实例与原型占用了相同的内存空间,所以这种方法非常不经济,另一种策略是欺骗系统的技术:写时复制。这种欺骗的典型示例就是操作系统中的动态链接库,它的内存区总是写时复制的,这种方法的远离就是当需要写对象的属性的时候,我们就复制一个原型的映像出来,并使以后的操作指向该映像。
显然上面的规则只是讲了对象的形成过程,而没有讲到构造过程,其实函数首先只是一个函数,尽管他有一个prototype成员,但如果每生命一个成员都先创建一个对象实例,并使prototype指向它,那么也不经济,所以我们事实上可以认为protytope在函数初始化时候根本是无值的,实现上可能是下面的逻辑
var _proto_ = null;
function get_prototype(){
if(!_proto_){
_proto_=new Object();
_proto_.constructor = this;
}
return _proto_;
}
所以,函数只有在需要引用到原型的时候,才具有构造器的特性。当一个函数的prototype有意义时,它就变成了一个‘构造器’。这是当new一个实例时,引擎会在构造一个对象,并使该对象的原型指向prototype的属性就可以了