JavaScript对象模型-执行模型一、数据类型1.基本数据类型基本数据类型是JS语言最底层的实现。简单数值类型:有Undefined,Null,Boolean,Number和String。注意,描述中的英文单词在这里仅指数据类型的名称,并不特指JS的全局对象Nan,Boolean,Number,String等,它们在概念上的区别是比较大的。对象:一个无序属性的集合,这些属性的值为简单数值类型、对象或者函数。同上,这里的对象并不特指全局对象Object。函数:函数是对象的一种,实现上内部属性[[Class]]值为Function,表明它是函数类型,除了对象的内部属性方法外,还有[[Construct]]、[[Call]]、[[Scope]]等内部属性。函数作为函数调用与构造器(使用new关键字创建实例对象)的处理机制不一样(Function对象除外),内部方法[[Construct]]用于实现作为构造器的逻辑,方法[[Call]]实现作为函数调用的逻辑。同上,这里的函数并不特指全局对象Function。函数在JS这个Prototype语言中可以看作是面向对象语言的类,可以用它来构造对象实例。既然函数可以看作是类,所以每一个函数可以看作是一种扩展数据类型。2.内置数据类型(内置对象)Function:函数类型的用户接口。Object:对象类型的用户接口。Boolean,Number,String:分别为这三种简单数值类型的对象包装器,对象包装在概念上有点类似C#中的Box/Unbox。Date,Array,RegExp:可以把它们看作是几种内置的扩展数据类型。首先,Function,Object,Boolean,Number,String,Date,Array,RegExp等都是JavaScript语言的内置对象,它们都可以看作是函数的派生类型,例如NumberinstanceofFunction为true,NumberinstanceofObject为true。在这个意义上,可以将它们跟用户定义的函数等同看待。其次,它们各自可以代表一种数据类型,由JS引擎用nativecode或内置的JS代码实现,是暴露给开发者对这些内置数据类型进行操作的接口。在这个意义上,它们都是一种抽象的概念,后面隐藏了具体的实现机制。在每一个提到Number,Function等单词的地方,应该迅速的在思维中将它们实例化为上面的两种情况之一。数据类型实现模型描述Build-in***datastructure:指JS内部用于实现***类型的数据结构,这些结构我们基本上无法直接操作。Build-in***object:指JS内置的Number,String,Boolean等这些对象,这是JS将内部实现的数据类型暴露给开发者使用的接口。Build-in***constructor:指JS内置的一些构造器,用来构造相应类型的对象实例。它们被包装成函数对象暴露出来,例如我们可以使用下面的方法访问到这些函数对象://PassedinFF2.0,IE7,Opera9.25,Safari3.0.4//accessthebuild-innumberconstructorvarnumber=newNumber(123);varnumConstructor1=number.constructor;//orvarnumConstructor2=newObject(123).constructor;//bothnumConstructor1andnumConstructor2arethebuild-inNumberconstructornumConstructor1==numConstructor2//result:true//accessthebuild-inobjectconstructorvarobjConstructor1={}.constructor;//orvarobjConstructor2=newObject().constructor;//bothobjConstructor1andobjConstructor2arethebuild-inObjectconstructorobjConstructor1==objConstructor2//result:true具体实现上,上图中横向之间可能也存在关联,例如对于build-indatastructure和constructor,Function、Date、Array、RegExp等都可以继承Object的结构而实现,但这是具体实现相关的事情了。关于简单数值类型的对象化这是一个细微的地方,下面描述对于Boolean,String和Number这三种简单数值类型都适用,以Number为例说明。JS规范要求:使用varnum1=123;这样的代码,直接返回基本数据类型,就是说返回的对象不是派生自Number和Object类型,用num1instanceofObject测试为false;使用new关键字创建则返回Number类型,例如varnum2=newNumber(123);num2instanceofNumber为true。将Number当作函数调用,返回结果会转换成简单数值类型。下面是测试代码://PassedinFF2.0,IE7,Opera9.25,Safari3.0.4varnum1=newNumber(123);//num1derivedfromNumber&Objectnum1instanceofNumber//result:truenum1instanceofObject//result:true//convertthenum1fromNumbertypetoprimitivetype,soit'snolongeraninstanceofNumberorObjectnum1=Number(num1);num1instanceofNumber//result:falsenum1instanceofObject//result:falsevarnum2=123;//num2isaprimitivetypenum2instanceofNumber//result:falsenum2instanceofObject//result:false虽然我们得到了一个简单数值类型,但它看起来仍然是一个JSObject对象,具有Object以及相应类型的所有属性和方法,使用上基本没有差别,唯一不同之处是instanceof的测试结果。Prototype继承Prototype每个对象都有一个[[Prototype]]的内部属性,它的值为null或者另外一个对象。函数对象都有一个显示的prototype属性,它并不是内部[[Prototype]]属性。不同的JS引擎实现者可以将内部[[Prototype]]属性命名为任何名字,并且设置它的可见性,只在JS引擎内部使用。虽然无法在JS代码中访问到内部[[Prototype]](FireFox中可以,名字为__proto__因为Mozilla将它公开了),但可以使用对象的isPrototypeOf()方法进行测试,注意这个方法会在整个Prototype链上进行判断。使用obj.propName访问一个对象的属性时,按照下面的步骤进行处理(假设obj的内部[[Prototype]]属性名为__proto__):1.如果obj存在propName属性,返回属性的值,否则2.如果obj.__proto__为null,返回undefined,否则3.返回obj.__proto__.propName调用对象的方法跟访问属性搜索过程一样,因为方法的函数对象就是对象的一个属性值。提示:上面步骤中隐含了一个递归过程,步骤3中obj.__proto__是另外一个对象,同样将采用1,2,3这样的步骤来搜索propName属性。例如下图所示,object1将具备属性prop1,prop2,prop3以及方法fn1,fn2,fn3。图中虚线箭头表示prototype链。这就是基于Prototype的继承和共享。其中object1的方法fn2来自object2,概念上即object2重写了object3的方法fn2。JavaScript对象应当都通过prototype链关联起来,最顶层是Object,即对象都派生自Object类型。类似C++等面向对象语言用类(被抽象了的类型)来承载方法,用对象(实例化对象)承载属性,Prototype语言只用实例化的对象来承载方法和属性。本质区别是前者基于内存结构的描述来实现继承,后者基于具体的内存块实现。对象创建过程JS中只有函数对象具备类的概念,因此要创建一个对象,必须使用函数对象。函数对象内部有[[Construct]]方法和[[Call]]方法,[[Construct]]用于构造对象,[[Call]]用于函数调用,只有使用new操作符时才触发[[Construct]]逻辑。varobj=newObject();是使用内置的Object这个函数对象创建实例化对象obj。varobj={};和varobj=[];这种代码将由JS引擎触发Object和Array的构造过程。functionfn(){};varmyObj=newfn();是使用用户定义的类型创建实例化对象。newFn(args)的创建过程如下(即函数对象的[[Construct]]方法处理逻辑,对象的创建过程)。另外函数对象本身的创建过程(指定义函数或者用Function创建一个函数对象等方式)虽然也使用了下面的处理逻辑,但有特殊的地方,后面再描述。1.创建一个build-inobject对象obj并初始化2.如果Fn.prototype是Object类型,则将obj的内部[[Prototype]]设置为Fn.prototype,否则obj的[[Prototype]]将为其初始化值(即Object.prototype)3.将obj作为this,使用args参数调用Fn的内部[[Call]]方法3.1内部[[Call]]方法创建当前执行上下文3.2调用F的函数体3.3销毁当前的执行上下文3.4返回F函数体的返回值,如果F的函数体没有返回值则返回undefined4.如果[[Call]]的返回值是Object类型,则返回这个值,否则返回obj注意步骤2中,prototype指对象显示的prototype属性,而[[Prototype]]则代表对象内部Prototype属性(隐式的)。构成对象Prototype链的是内部隐式的[[Prototype]],而并非对象显示的prototype属性。显示的prototype只有在函数对象上才有意义,从上面的创建过程可以看到,函数的prototype被赋给派生对象隐式[[Prototype]]属性,这样根据Prototype规则,派生对象和函数的prototype对象之间才存在属性、方法的继承/共享关系。用代码来做一些验证://PassedinFF2.0,IE7,Opera9.25,Safari3.0.4functionfn(){}//thevalueofimplicit[[Prototype]]propertyofthoseobjectsderivedfromfnwillbeassignedtofn.prototypefn.prototype={attr1:aaa,attr2:bbb};varobj=newfn();document.write(obj.attr1+br/);//result:aaadocument.write(obj.attr2+br/);//result:bbbdocument.write(objinstanceoffn);//result:truedocument.write(br/);//Ichangetheprototypeoffnhere,sobythealgorithmofPrototypetheob