1 window.undefined = window.undefined;
在较老的浏览器中,如IE5之前的浏览器,undefined并不是window对象的一个子对象,并不是一个已实现的系统保留字,而是代表一个未定义类型,除了直接赋值和typeof()之外,其它任何对undefined的操作都将导致异常。如果需要知道一个变量是否是undefined,只能采用typeof()的方法:如var v;if (typeof(v) == 'undefined') {// ...}。如果使用if(a==="undefined")则会报“undefined未定义”的错误。
因此为了兼容IE5及之前的浏览器,我们可以使用一些方法来解决这个问题。本文前面说到的就是其中一种方式。window.undefined=window.undefined;咋一看很难理解,写法有点bt,但理解一下就不觉得奇怪了,在较早的浏览器中因为window.undefined不存在所以会返回undefined,将此赋给等号前的window.undefined这样后面就可以直接使用if(a==="undefined")的判断方式了。在新版本的浏览器中window.undefined=undefined;因此不会造成什么负面影响。
除了使用window.undefined=window.undefined和window["undefined"]=window["undefined"]外,还有很多别的办法来实现对IE5及之前浏览器的兼容,如
var undefined = void null; //void函数永远返回undefined
var undefined = function(){}();
var undefined = void 0;
只要等号后的表达式返回undefined即可。
2 Ext.apply
/**
* 将config对象的所有属性拷贝到obj对象。
*参数:
obj : Object 接收属性的对象
config : Object 提供属性的对象
defaults : Object 一个不同的对象,属性可以作为默认值被拷贝。
*返回值:
Object
returns obj
*/
Ext.apply = function(o, c, defaults){
// no "this" reference for friendly out of scope calls
if(defaults){
Ext.apply(o, defaults);
}
if(o && c && typeof c == 'object'){
for(var p in c){
o[p] = c[p];
}
}
return o;
};
3/**
*作用:是
*/
(function(){
相关处理代码
......
})();
大家知道小括号的作用吗?小括号能把我们的表达式组合分块,并且每一块,也就是每一对小括号,都有一个返回值。这个返回值实际上也就是小括号中表达式的返回值。所以,当我们用一对小括号把匿名函数括起来的时候,实际上小括号对返回的,就是一个匿名函数的Function对象。因此,小括号对加上匿名函数就如同有名字的函数般被我们取得它的引用位置了。所以如果在这个引用变量后面再加上参数列表,就会实现普通函数的调用形式。
function(){相关处理代码......}申明了一个匿名函数,()返回匿名函数对象的引用,后面一个(),调用对象。
4 Ext.extend函数
JavaScript继承实现一:
js call() 方法:
Class1.call(this) 的 意思就是使用 Class1 对象代替this对象,那么 Class2 中不就有Class1 的所有属性和方法了吗。
function Person(name,food){
this.name=name;
this.eat=function(){
alert(name+" eat "+food);
}
}
function Boy(food){
Person.call(this,"boy",food);//调用父类的构造方法
}
function Girl(food){
Person.call(this,"girl",food);//调用父类的构造方法
}
var b=new Boy("fish");
b.eat();
JavaScript继承实现二:
(1) prototype constructor
RectAngle=function (width,height){
this.width=width;
this.height=height;
}
RectAngle.prototype.area=function(){
return this.width*this.height;
}
每个函数都有一个prototype属性,构造函数也是函数,所以也有prototype属性。prototype属性在定义函数的时候会自动创建并初始化.也就是说,在写下RectAngle=function(widht,height){//...}的时候,RectAngle的prototype属性就已经被创建了,这个时候prototype里面只有一个属性,它就是constructor(构造器),这个constructor指回了RectAngle函数本身。
对于每个RectAngle的实例来说,例如var rect=new RectAngle(10,10); rect.prototype会指向构造函数RectAngle的prototype,也就是说所有的实例都会共享同一份RectAngle.prototype,
如此,就不需要分配那么多内存给每个实例来存储prototype属性了。
(2) js通用继承方式:
RectAngle=function(w,h){
this.w=w;
this.h=h;
}
RectAngle.prototype.area=function(){
return this.w*this.h;
}
写个子类来继承RectAngle,这个子类叫做有颜色的矩形ColoredRectAngle,多一个color属性。
ColoredRectAngle=function(color,w,h){
RectAngle.call(this,w,h); //继承属性
this.c=color;
}
上面已经把w和h属性拷贝到子类中来了,父类的prototype里面还有个area方法也得想办法拷贝进来,注意了,这是精彩的部分,不能错过哦。
ColoredRectAngle.prototype=new RectAngle();//这个写法其实包含了很多内容哦,我们把它拆开来写会更好理解
var rect=new RectAngle();
ColoredRectAngle.prototype=rect;//怎么样,含义是一样的吧?
好,开始分析这两句话。rect是RectAngle的实例(废话,它是由RectAngle构造函数构造出来的,当然是它的实例了!),但是
在构造rect的时候,没有传参数给它,这样的话在rect这个对象里面w和h这两个属性就是null(显然必须的)。
既然rect是RectAngle的实例,那么它的prototype会指向RectAngle.prototype,所以rect对象会拥有area()方法。
另外,rect.prototype.constructor指向的是RectAngle这个构造函数(显然必须的)。
好,现在ColoredRectAngle.prototype=rect,这一操作有三个问题,第一,rect的w和h被放到ColoredRectAngle.prototype里面来了,第二,rect.prototype.area()这个方法也到了ColoredRectAngle.prototype里面了,当然,完整的访问area()方法路径应该是ColoredRectAngle.prototype.prototype.area(),但是因为JavaScript的自动查找机制,放在prototype里面的属性会被自动找出来(加入从对象的直接属性里面找不到的话。)这样就没有必要写完整的访问路径了,直接写ColoredRectAngle.area()就可以找到area()了,看上去就好像ColoredRectAngle也拥有了area()方法。
值得注意的一点是,在执行RectAngle.call(this,w,h);这一步的时候我们已经把w和h两个属性拷贝到ColoredRectAngle里面了,这里我们不再需要rect里面这两个值为null的w和h,
所以,直接把它们删除了事,免得浪费内存。
Delete ColoredRectAngle.prototype.w;
delete ColoredRectAngle.prototype.h;
OK,到了这一步,看起来模拟继承的操作就算大功告成了,父类RectAngle的w和h属性通过RectAngle.call(this,w,h)拷贝进来了,父类prototype里面的方法也拷贝进来了,没用的废物(rect里面,也就是ColoredRectAngle.prototype里面,值为null的w和h)也剔除掉了。
看上去世界一片和谐。但是...还有一个暗藏的问题,请看:第三:这个时候ColoredRectAngle类的constructor指向错了。
本来,如果没有ColoredRectAngle.prototype=rect这步操作,ColoredRectAngle.prototype就是JavaScript自动创建出来的那个prototype,这个prototype有个constructor,指向了ColoredRectAngle构造函数自己.
但是,现在ColoredRectAngle.prototype=rect,如果现在来访问ColoredRectAngle.prototype.constructor,那么,根据自动查找机制,会找到rect.prototype.constructor,但这个constructor指向的是父类RectAngle构造函数,这个就不符合prototype的游戏规则了。因为,如果此时
var coloredRectAngle=new ColoredRectAngle('red',10,10) alert(coloredRectAngle.constructor);
得到的是父亲RectAngle的构造函数,从面向对象的观点看,这个结果是可以理解的,毕竟,子类对象也可以看成是父类对象。
但是,这样的话对于ColoredRectAngle的实例来说,就不能确切地知道它的constructor是ColoredRectAngle了。
所以,需要手动地把ColoredRectAngle.prototype.constructor设置回来。于是有了这一步:ColoredRectAngle.prototype.constructor=ColoredRectAngle.