调试js代码时经常需要用到alert(),每次都要听到刺耳的‘当…’,于是就自己编写了一个简短的调试信息输出的函数debug。最近又在jQuery框架,于是就仿照其编写风格改进了一下。下面就把笔者在这个过程中的一些心得说出来,供大家参考。
一、函数实现的自定义调试函数debug
平常大家所用到的alert(msg),作用是把msg打印到警告框,虽然在编写代码时比较方面省事,但缺点也是很明显的,那就是每次都要点击,并且还有扰人的警告声。笔者所实现的debug函数,基本功能也跟alert(msg)类似,不同的是不需要点击。其把信息打印到一个个具有类名为debug_output的div里,并加上合适的样式,醒目而且不扰人。实现的代码如下,用到了jQuery库,而且我把jQuery.noConflict()打开,为的是能在不同的库共存(我所参与的项目要在Discuz!中加入jQuery库,而前者的common.js中也实现了$(),并且与jQuery不同):
function debug(s) { //向文档(DOM)中添加一个存放调试信息的容器,以及通过调用puts方法将调试信息加入到文档中并显示出来。 //debug_container采用绝对定位布局在文档中,保证当有输出时总是可见 if(!jQuery('#debug_container').length) jQuery('<div id="debug_container"></div>').appendTo('body') .css({ position: 'absolute', top: '300px', width: '100%', index: 99 }); //向#debug_container中添加带有类debug_output的div jQuery('<div class="debug_output"><em style="margin-right:5px;">Output:</em> </div>').appendTo('#debug_container'); //搜索指定类名的div,并向其中加入要输出的调试信息,以及为了突出显示和美观而添加的样式。因为要把调试信息加入到最后一个拥有指定类名的div(原因大家可想象一下),所以用到了:last选择器 var thisAlert = jQuery('div.debug_output:last'); thisAlert.append('<em class="content">'+ s +'</em>').css ({ border: '1px solid #f00', 'font-family': '"Courier New", monospace', background: '#fcc', width: '100%', 'margin-top': '5px' }); }
在页面中插入以下代码作为测试:
//Output: testing debug('testing');
本文笔者将以此函数为例,将一个普通的函数改造成构造类,进而在此基础上探讨jQuery式的封装。不过在开始之前,先将本文中涉及到的javascript的类和封装基本知识概述一下,有基础的读者可选择跳过。
必要的知识准备:javascript类和封装 现行的编写javascript的方法共有三种,即工厂模式、构造函数模式和原型模式,而用得最多的不是其中的哪一种,而是后两者的混合方式。面向对象编程(Object Oriented Programming,简称OOP)领域的类的概念通常包含属性(Attributes)和方法(Methods),但是在javascript里并没有明确的类的概念,所以我们以特定的方法编写函数让其实现类的功能。考虑以下的代码(混合模式): //注:这段代码仅供演示概念之用,在实际编程中这种无意义的代码是没有任何用处的 function OO(s) { //在构造函数中规定类的属性 this.test = s; } OO.prototype = { //在原型(prototype)中绑定方法,则每一个类的实例都将拥有这样的一个方法的副本 init: function(s) { this.trace(); }, trace: function() { alert(this.test); } }; //在使用类之前必须进行实例化,下面的代码将产生一个错误:对象不支持此属性或方法 OO.init(); //应用以下的方式初始化一个OO类的实例 var o = new OO(‘This is a testing!’); //调用类的实例方法 o.init();//弹出警告框:This is a testing! o.trace();//弹出警告框:This is a testing!
如果读者对javascript类和封装不甚明了,或者有兴趣继续研究的话,参考这篇文章。
二、jQuery式的自定义对象Debug
不忙写代码,先把jQurey中的选择器$的实现原理简要分析一下。笔者摘录了jQurey v1.3.2的部分代码,这些都是实现$的关键和核心,方便讨论。
jQuery $选择器的核心实现代码 //第一点要说的就是(function() {})(),闭包。更多关于闭包的信息请浏览[url=http://www.cnblogs.com/zhangle/archive/2010/07/02/1770206.html这篇文章[/url] (function(){ var //涉及到作用域的问题,window.$( window.jQuery)是为了能在闭包之外访问到$ window = this, jQuery = window.jQuery = window.$ = function(selector, context){ //使用了new运算符,在变量$(jQuery)创建时即被实例化,而不是只声明了一个构造类 return new jQuery.fn.init(selector, context); }; jQuery.fn = jQuery.prototype = { //这个是$(或jQuery)被创建时自动执行的函数 init: function( selector, context ) { //实现代码略 } } //最后,把debug的原型赋值给debug的方法init,关于这点请读者认真思考:因为创建debug对象时是采用返回函数的形式(return new debug.fn.init(s);),所以debug现在的prototype属性实际上指向debug.fn.init.prototype。如果不在最后反赋值的话,debug.fn.init中是没有办法访问到this.puts()的,这时浏览器报错,不存在该属性或方法 jQuery.fn.init.prototype = jQuery.prototype; })();
为了更好地理解jQuery的实现原理,请考虑下面这个小程序,同样注意它纯为演示功能所写,在实际编程实践中是没有意义的。
(function() { var OO = window.OO = function(s) { this.test; return OO.fn.init(s); }; OO.fn = OO.prototype = { init: function(s) { this.test = s; this.testing(); }, testing: function() { alert(this.test); } }; OO.fn.init.prototype = OO.prototype; })();
通过下面的代码调用OO,注意此时OO在创建时就已经被初始化了,因此不需要new关键字。
//弹出警告框:testing OO('testing');
写到这里,结合前述调试函数,一个自定义的调试类已经呼之欲出了。只要把函数的代码稍作修改,加入到jQuery式的框架内即可。代码如下:
(function() { var // window = this, Debug = window.Debug = function(s) { return new Debug.fn.init(s); }; Debug.fn = Debug.prototype = { init: function(s) { if(!jQuery('#debug_container').length) jQuery('<div id="debug_container"></div>').appendTo('body') .css({ position: 'absolute', top: '300px', width: '100%' }); this.puts(s); }, puts: function(s) { //向#debug_container中添加带有类debug_output的div jQuery('<div class="debug_output"><em style="margin-right:5px;">Output:</em> </div>').appendTo('#debug_container'); var thisAlert = jQuery('div.debug_output:last'); thisAlert.append('<em class="content">'+ s +'</em>').css ({ border: '1px solid #f00', 'font-family': '"Courier New", monospace', background: '#fcc', width: '100%', 'margin-top': '5px' }); } }; Debug.fn.init.prototype = Debug.prototype; })();
将这段代码加入到文档中,在任何需要查看输出信息的地方添加如下代码,就像原来的alert一样方便,但是体验却更加美好。
//Output: testing Debug('testing');
三、文中涉及到的知识
(1)jQuery的基本使用技巧,点此深入了解。
(2)闭包,点此深入了解。
(3)对象的原型prototype,点此深入了解。
(4)javascript类和对象的概念,点此深入了解。