jQuery实现原理浅析——一个调试类的实现

调试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的基本使用技巧,[url=http://bbs.jquery.org.cn/]点此深入了解[/url]。
(2)闭包,[url=http://www.cnblogs.com/zhangle/archive/2010/07/02/1770206.html]点此深入了解[/url]。
(3)对象的原型prototype,点此[url=http://hi.baidu.com/shoiphy/blog/item/fe4f66080e1055980a7b8216.html]深入了解[/url]。
(4)javascript类和对象的概念,[url=http://www.iteye.com/topic/288808]点此深入了解[/url]。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值