一、对象从何而来
首先来看什么是对象,搜索wiki百科可以得到解释,在面向对象(Object Oriented) 的软件中,对象(Object)是某一个类(Class)的实例(Instance) ,因此说有对象之前必须先有类型,然后再将类型实例化就得到了对象。
那么在JavaScript中,类型不是通过如java的声明的方式定义,而是通过function的方式获得的,如
1: function DemoClass(){}
2:
3: var x = new DemoClass();
注意:这个顺序不能改变,必须先有function才能获得对象,否则会出现脚本错误,这是因为JavaScript的解析器是按顺序解析的,如果使用了还未被解析的function就会出现错误,由于这类function用来构造对象,把这类function叫做构造器
二、构造器的结构
每个构造器都有prototype属性,这个属性的结构是字典,可以任意添加名-值对组合,如
1: function DemoClass(){}
2:
3: DemoClass.prototype.Name = "DemoClass";
4:
5: DemoClass.prototype.IsNum = function(){return ture;};
同时每个构造器的prototype属性都有一个constructor属性指向构造器自身,构造器的prototype的类型为Object
三、对象的结构
每个对象都有__proto__只读属性,这个属性指向构造器的prototype属性。
除此之外,对象还有一个隐藏的内部属性,这个属性结构也是字典,可以任意添加名-值对组合
因此修改了构造器的prototype字典,所有由该构造器生成的对象的属性就会发生改变,如果只是对一个对象实例修改了属性,其他对象实例不会受到影响,如
1: function DemoClass(){}
2: DemoClass.prototype.Name = "DemoClass";
3: DemoClass.prototype.IsNum = function(){return ture;};
4: var x = new DemoClass();
5: var y = new DemoClass();
6: DemoClass.prototype.Name = "DemoClass1"; /* x.Name == y.Name */
7: x.Name = "DemoClass2"; /* x.Name != y.Name */
四、对象属性的读取和修改
由于每个对象实际上都会有两个字典,因此必然要有先后顺序,而且读取和修改的策略也不同
读取时,首先从对象自身的字典中读取,若找到则返回,未找到时再从__proto__指向的字典中查找,若找到则返回,若未找到则返回undefined。
修改时,直接向对象自身的字典中添加或修改,不对__proto__指向的字典操作
这样的策略保证了对单个对象属性的修改不会影响到其他对象,同样的对象在不同的运行时环境里就有了不同的行为即“动态性”。
五、再看构造器
看如下代码
1: function DemoClass(){}
2: DemoClass.prototype.Name = "DemoClass";
3: function DemoClass1(){}
4: DemoClass1.prototype.Name = "DemoClass1";
5: var x = new DemoClass();
6: var y = new DemoClass1();
声明两个构造器并且给每个构造器都实例化了对象,通过测试发现,两个构造器的prototype所指的字典并不相同,但是类型都为object
从这些可以看出,构造器被调用时,其prototype属性是一个object的实例,下面是用C来描述构造器和对象的结构
1: //构造器
2: struct Constructure{
3: object prototype;
4: Constructure(){
5: this.prototype = new object();
6: this.prototype.constructor = this;
7: }
8: }
9: //对象
10: struct Instance{
11: Constructure* __proto__;
12: object innerdict;//内部的字典
13: Instance(){
14: this.innerdict = new object();
15: this.__proto__ = JSRuntime["Constructure"];//通过运行时获取构造器地址
16: }
17: }