为了减少命名冲突,最好的办法是定义一个全局变量,并将其他变量和方法定义为该全局变量的属性。
var MYAPP = MYAPP || {}; MYAPP.event = { addListener:function(el,type,fn){ // .. do the thing } removeListener:function(el,type,fn){ // ... } // ... other methods or properties };
我们也可以在命名空间中使用构造函数,一般使用大写开头表示构造函数:
MYAPP.dom = {} //创建元素节点 MYAPP.dom.Element = function(type, prop){ var tmp = document.createElement(type); for(var i in prop){ tmp.setAttribute(i,prop[i]); } return tmp; } //创建文本节点 MYAPP.dom.Text = function(txt){ return document.createTextNode(txt); }
下面使用构造函数来创建一个链接:
//Element对象 var el1 = new MYAPP.dom.Element('a',{href:'http://phpied.com'}); //Text对象 var el2 = new MYAPP.dom.Text('click me'); el1.appendChild(el2); document.body.appendChild(el1);
不同的浏览器对于相同或相似的方法可能有不同的实现。这时,需要依据当前的浏览器版本来选择对应的执行分支。我们可以在加载脚本是,在模块初始化的过程中就将部分代码进行分支处理。
//先声明事件处理方法 var MYAPP={}; MYAPP.event={ addListener:null, removeListener:null }; //模块初始化进行定义,它们将根据具体的浏览器特性探测的结果,被赋予不同的实现 if(typeof window.addEventListener === 'function'){ MYAPP.event.addListener = function(el, type, fn){ el.addEventLIstener(type, fn ,false); } MYAPP.event.removeListener = function(el, type, fn){ el.removeEventListener(type, fn, false); } }else if(typeof document.attachEvent === 'function'){//IE MYAPP.event.addListener = function(el, type, fn){ el.attachEvent('on'+type,fn); } MYAPP.event.removeListener = function(el, type, fn){ el.detachEvent('on'+type,fn); } }else{//older browsers MYAPP.event.addListener = function(el, type, fn){ el['on' + type] = fn; } MYAPP.event.removeListener = function(el, type, fn){ el['on' + type]=null } }
一旦上述脚本被执行,我们就定义了与浏览器特性相关的addListener()和removeListener()方法。如此,当它们再次被调用时,就不需要在探测浏览器特性了,脚本会执行得更快。
延迟定义模式与初始化分支模式很相似。不同之处在于,该模式下的分支只有在相关函数第一次被调用时才会发生,即只有函数被调用时,它才会以最佳实现改写自己。下面的addListener()方法将以泛型的方式来实现,即在它第一次被调用时,首先会检查浏览器支持的功能,然后为自己选择最合适的实现,最后调用自身以完成事件添加。
var MYAPP={}; MYAPP.myevent={ addListener:function(){ if(typeof el.addEventListener === 'function'){ MYAPP.myevent.addListener = function(el, type, fn){ el.addEventListener(type, fn, false); }; }else if(typeof el.attachEvent === 'function'){ MYAPP.myevent.addListener = function(el, type, fn){ el.attchEvent('on' + type, fn); }; }else{ MYAPP.myevent.addListener = function(el, type, fn){ el['on' + type]=fn; }; } MYAPP.myevent.addListener(el,type,fn); } }
下面,假设我们要设计一个Button构造器,将其用于创建输入性按钮。它的参数包括一段文本,即按钮显示的内容和一个可缺省的type参数:
var MYAPP={}; MYAPP.dom={}; MYAPP.dom.Button=function(text,type){ var b = document.createElement('input'); b.type = type || 'submit'; b.value = text; return b; }
该构造器很简单,只需传递给它一个字符串,然后就可以把新创建的按钮加入文档:
document.body.appendChild(new MYAPP.dom.Button('puuush'));
但是接下来,我们需要为按钮设置更多的属性,例如颜色和字体。结果,这个构造器的定义最终就可能变成这样:
MYAPP.dom.Button = function(text, type, color, border, font){ // .... }
这显然就不太方便了,比如当我们可能只想设置第三个和第五个参数,就必须这样:
new MYAPP.dom.Button('puuush',null,'white',null,'Arial, Verdana, sans-serif');
这个时候,更好的选中就是用一个可配置的对象参数来代替所有的参数配置:
MYAPP.dom.Button = function(text, conf){ var type = conf.type || 'submit'; var font = conf.font || 'Verdaba'; // ... }
var config = { font:'Arial, Verdana, sans-serif', color:'white' }; new MYAPP.dom.Button('puuush',config);
var MYAPP={}; MYAPP.dom=(function(){ var _setStyle = function(el, prop, value){ el.setAttribute(prop,value);return this; } var _getStyle = function(el, prop){ console.log('getStyle'); } return { setStyle:_setStyle, getStyle:_getStyle }; })(); //创建元素节点 MYAPP.dom.Element = function(type, prop){ var tmp = document.createElement(type); for(var i in prop){ tmp.setAttribute(i,prop[i]); } return tmp; } var obj = new MYAPP.dom.Element('span');
总所周知,构造器返回的是新建对象的this指针。通过让setStyle()方法返回this,这样,我们就可以直接用这些方法所返回的实例来调用其他方法,这就是所谓的链式调用:
JSON本身实际上是一种轻量级的数据交换格式,由对象和数组标记的数据构成。
{ 'name':'Stoyan', 'family':'Stefanov', 'books':['phpBB2','phpBB UG','PEAR'] }
假设服务器返回该JSON字符串,它保存在resp变量中,然后,我们调用eval()将该字符串转换为JavaScript对象:
var obj = eval('('+resp+')');
接着,我们就可以通过obj的属性来访问这些数据了:
alert(obj.name);
alert(obj.books[2])