返回深入学习ExtJS 2.2开发系列连载教程目录
对于变量或对象的类型判断是经常用到的功能,也是每门语言都提供的功能。在C中就提供typeof要判断类型。但是在面向对象中这种判断是不准的。如我通过private Animal cat=new Cat();Cat类是继承Animal类的。如果采用typeof来判断的话,cat的类型是Animal。这样的类型当然是没有错的。但是我们需要的是返回Cat类型。于是面向对象语言大部分都提供了instanceof来判断其运行实例的真正的类型。
typeof分析
Js语言的中typeof也是出现这样的问题。它可以返回六种类型:number、string、boolean、object、function、undefined。对于这六种类型,我们做了下面的测试
从上面的代码可以看不管是空字符,还是空格,它都当作是string的类型。对于boolean的类型,就是true和false两种。对于 Number类型而言,NaN也就是属于这个类型。undefined的本身或变量没有定义或变量没有初始化(仅仅是定义了)都返回undefined。
上面string,boolean,undefined,number这四种是我们可以接受的类型判断。但是对null的返回值为object,对于通过new原生对象(如Array,Date,String等)的返回值都是object。这个就是不是我们所需要的。对于原生对象本身,它们返回的类型是function。我们也不太满意。
从上面的例子可以看出。原生对象本质其实都是函数类型。Function是构建函数的函数,而new Function()则是构建之后的函数。
为了更好地满足目前的要求。我们应该把对数组等的类型的返回值再精准一步,让其返回Array的类型。而对于null的返回类型应该和undefined一样,返回false。
Ext.type函数
Ext.type则改进了上面的所提出的问题,同时还提供了一些关于元素常用节点的判断。在上一部分,我们可以看出通过new的方式构建的(除Function)都是对象(还有一些直接量,如,{})。那么我们如果把其实质为object的类型更精准一点呢。Array,Date这样原生对象其实都函数。也就是说明原生对象的实例都会有有一个constructor的属性。我们可以通过这个constructor来区分。对于dom元素的节点的类型来讲,我们要先要判断是不是节点,再判断其nodeType是什么类型。Mootools做了很多开创性的工作,它的$type也成为别的类库借鉴的东西。Ext.type就是来自mootools的$type。
通过Ext.type,我们可以判断regexp,array,nodelist等类型。这个只是提供了一个简单的代码,并没有从根本上解决面对对象中instanceof的问题。在mootools1.2中提供了一个更为完美的解决方案。但是那是建立在整个框架的重新架构之上。其实Ext.type已经足够用了,不需要完全的面向对象化。
3.1.3 命名空间的分析
对于命名空间,它实际上就是一个变量,在window的定义的是全局变量,在变量对象或函数中定义的就是局部变量。但是我们不是把这个变量当作存储值来看待或使用。我们把它当作一组或一类东西(函数,类)的空间或领域的归类来看待,同一类或同一组的函数(类)都在同一个命名空间(变量)中。这样变量就成了C#的命名空间或Java中包的概念。
对于Ex.namespace函数,相信基本上是没有人会用到的。因为它的适用的场合也不多。但是其作用却是蛮大的。通过它,我们不需要为每个子命名空间来定义。如Ext.Event.MM空间,我们得通过Var Ext={}, Ext.Event={},Ext.Event.MM来定义。而现在只要通过Ex.namespace(” Ext.Event.MM”)直接定义就可以了。
Ex.namespace的实现也是值得分析的,它通过eval来动态生成命名空间。分析它之前,我们先看一下eval函数。命名空间采用函数来指定的话,也许很多读者觉得没有必要或思虑其的实现机制。
Eval函数的分析
Eval函数能把字符串当作JavaScript表达式或语句一样执行,也就是说我们能通过string的形式来动态地组建来执行的JavaScript语句或其表达式。可以看出Eval函数的功能强大且灵活。
我们可以通过它来计算如”3+5”字符串的数字表达式。我们可以执行如”if(!xx) var xx={}”这样动态字符串的语句。我们还可以通过eval(”({xx:YY})”)来把json字符串转换Json对象。
其格式:Eval(codeString,[override])。
参数 :codeString 必选。JavaScript表达式或语句的字符串。
override 可选项。指执行代码的安全权一般采用默认。
我们可以把Eval支持的codeString分成两种类型:表达式和JavaScript语句。对于表达式而言,Eval能执行或计算它并返回它的结果值。对于Json字符串,把其加上()中间,就是把其转换表达式来处理。不加的话,它就会当作语句来执行,这时的{}就解释成域的范围,计算其第一个属性值并返回。对于JavaScript语句,运行时所在上下文和和eval方法的上下文一样。即其中出现的变量或函数调用必须在eval的上下文环境中是可用的。在第二章中对于默认生成类名的处理就可以用到eval。
加强 增加性能的比较,采用function等自己构建一个eval
Ext.namespace分析
Ext.namespace能一次分配多个命名空间。命名空间可以采用点串(如Ext.Event)的形式来分配。对于和已经存在的命名空间相同的话,就直接采用存在的空间。如Ext自己就采用了它来为自己的类库分配了命名空间:
Ext. namespace:
namespace : function(){我们来通过Ext.util这个命名变量来分析一下Ext. namespace内的eval的操作。首先把Ext.util分成两部分,存在d=[Ext, util]的数组中。对于Ext字符,它生成如下的语句:
if (typeof Ext =="undefined"){ Ext = {};} o = Ext;
这一句的上下文是namespace这个函数的内部。这里的Ext在函数内部没有定义,再看看是全局变量。在全局已经定义了。如果没有定义,就在全局生成一个Ext变量空间,其为{}的空对象。接下的o = Ext把Ext这个变量或命名赋值给o这个函数内部的变量。
在接下来的for循环中,先通过o[d[j]]看看Ext的变量空间是否有util这个变量命名,没有或其为空值(undefined)的话,就给Ext的变量空间增加一个util:{}的变量命名。接下把o这个变量指向这个uitl变量命名。进行点串中的下一个子命名空间的分配。这里就没有了。
在上面的代码中,可以看出其实现还是蛮巧妙的。Ext还提供了Ext.ns为Ext.namespace的缩写。我们在开发应用系统时,也是会对于Ext.ns的应用的,因为对于一个采用JavaScript的开发的富客户端。不采用一定的命名规则,其结果是很乱的。比如在本书的例子办公系统就采用了Ext.ns("Morik","Morik.Office", "Morik.Util");这样的方式要给应用系统分层次地命名。
这一节中,我们就Ext类中的extend,type,namespace进行了分析。因为这几个函数有一定的难度且对于整个类库都是很重要的。通过这一节,我们能把握Ext类的设计与实现。