jQuery的运行机制和设计理念分析


Posted in Javascript onApril 05, 2011

其短小精悍,使用简单方便,性能高效,能极大地提高开发效率,是开发Web应用的最佳的辅助工具之一。因此大部分开发者在抛弃Prototype而选择jQuery来进行Web开发。

一些开发人员在使用jQuery时,由于仅仅只知道jQuery文档中的使用方法,不明白jQuery的运行原理,时常会碰到许多的问题。这些问题大部分是使用不当而产生,极少数是jQuery的Bug。如果不明白其运行机理和核心源码,我们也很难写出基于jQuery类库的高性能的程序出来。

在调试基于jQuery的程序时,我们大部分时间都要跟踪进入jQuery对象分析其运行的状态,但是jQuery代码不像Ext,YUI那样中规中举,它的代码有点晦涩,难懂。也就说如果想用好jQuery,一定要清楚其源码。

jQuery的设计理念

使用jQuery之前,我们都会问jQuery是什么?jQuery是一个类库,和prototype,mootools等类库一样,为Web的 JavaScript开发提供辅助功能。那为什么要选用jQuery呢?在jQuery出现之前,Prototype,YUI都是很成熟的Js的框架,而且是各有各的特点。为什么要抛弃它们,而使用后起之秀的jQuery,它有什么优秀的特性吸引开发人员呢?

回答这个问题,我们得明白jQuery的设计理念。回忆或想象一下,我们在Web开发中是如何使用JavaScript?绝大多数时间都是采用 getElementById在Dom文档中找到DOM元素,然后取值或设定值,采用innerHTML取其内容或设定其内容,或进行事件的监听(如 click),在控制样式方面,我们会进行height,width,display等的改变,达到视觉上的效果,对于Ajax方面,也是取到数据在页面的某元素里面去添充内容。

综之,我们就是在对DOM元素在进行操作。这个元素可能是一个或是多个。这个元素可能是Document,Window或DOM元素。这样我们的任务就是二大部分,一是找DOM元素,二是对DOM元素进行操作。

对于用得熟练一点,不管是采用如getElementById这样的直接查找方式还是采用如Element.lastChild这类的间接查找方式不是很难的,对于DOM元素,DOM的操作方面也是很丰富,也不是很难使用?那么要类库做什么用呢?最难的一个问题就是浏览器的兼容的问题。所有的 JavaScript框架都要解决这一个问题,同时简化JavaScript的本身自带的操作。

Prototype可以说是开创了Js类库的先河,给我们耳目一新的感觉。它解决大部分的浏览器的兼容的问题。同时简化了原始函数名长难于记忆的经常书写出的错的问题(采用$(xx)代替getElementById),提供了Ajax的访问方式,扩展了 Array,Object,Function,Event等JavaScript原生对象。

但是这些还是不能满足开发的需要,比如在DOM树中寻找DOM元素,仅仅只能是通过元素的ID,但是我们想要更方便的查找方法,同时还希望能有一个统一的入口,不要太泛,学习曲线过高或难于使用。

jQuery就是从这里出发,把所有一切都统一在jQuery对象中。使用jQuery就是使用jQuery对象。其实jQuery开创性的工作就是如其名一样:query。它强大的查找功能令所有的框架都黯然失色。jQuery实质就是一个查询器。在查询器的基础还提供对查找到的元素进行操作的功能。这样说来jQuery就是查询和操作的统一。查询是入口,操作是结果。

jQuery在实现上也可以分成两大部分,一部分是jQuery的静态方法,也可以称作实用方法或工具方法,通过jQuery.xxx()的 jQuery命名空间直接引用。第二部分是jQuery的实例方法,通过jQuery(xx)或$(xx)来生成jQuery实例,然后通过这个实例来引用的方法。这部分的方法大多数是从采用静态方法代理来完成功能。真正的功能性的操作都在jQuery的静态方法中实现。这些功能细分起来,可以分成以下几个部分:

1、Selector,查找元素。这个查找不但包含基于CSS1~CSS3的CSS Selector功能,还包含其对直接查找或间接查找而扩展的一些功能。

2、Dom元素的属性操作。Dom元素可以看作html的标签,对于属性的操作就是对于标签的属性进行操作。这个属性操作包含增加,修改,删除,取值等。

3、Dom元素的CSS样式的操作。CSS是控制页面的显示的效果。对CSS的操作那就得包含高度,宽度,display等这些常用的CSS的功能。

4、Ajax的操作。Ajax的功能就是异步从服务器取数据然后进行相关操作。

5、Event的操作。对Event的兼容做了统一的处理。

6、动画(Fx)的操作。可以看作是CSS样式上的扩展。

jQuery对象的构建

生成或构建一个jQuery对象其实就是构建并运行一个查询器(selector)。既然是查询,肯定会查找的结果(DOM元素),之后才会有对这些结果进行操作。那么这些查找的结果存放在哪里呢?最好的地方当然是这个jQuery对象内面。查找的结果可能是一个元素,也有可以是多个元素如 (NodeSet的集合的形式)。也就是说jQuery对象内面有一个集合。这个集合存放查找到DOM元素。

但是上一小节所提到jQuery对象是所有操作的统一入口,那么它的构建就不能只局限于从DOM文档中查找到DOM元素,还有可能是从别的集合中转移过来的Dom元素,还有可能是从HTML的字符串生成的DOM元素。

在jQuery文档中提供了四种方式:jQuery(expression, [context]),jQuery(html),jQuery(elements),jQuery(callback)四种构寻jQuery对象的方式。其中jQuery可以用$代替。这四种是经常用到。其实jQuery的参数可以是任何的元素,都能构成jQuery对象。

举几个例子:

1、$($("P"))可以看出其参数可以是jQuery对象或ArrayLike的集合。

2、$()是$(document)的简写。

3、$(3)会把3放到jQuery对象中集合中。

对于如$(3)这样的其中元素(如ArrayLike集合的元素)不是DOM元素,最好不要构建jQuery对象,jQuery对象的方法都是针对于DOM对象的。不是很清楚其使用的话,很有可能会导致错误。上面讲了这么多,还是很难明白其原理的,现在从源码的角度细细分析:

通过jQuery(xxx)的调用实现没有生成对象,它的this是指向Window对象的。那么jQuery的那些实例方法是怎样继承过来的呢?看一下:

var jQuery = window.jQuery = window.$ = function(selector, context)
{ return new jQuery.fn.init(selector, context);
};
这是jQuery的总的入口,jQuery对象实际上不是通过new jQuery()而继承其prototype的中的方法。jQuery对象实际是jQuery.fn.init函数生成的对象。在里我们可以看出对于 jQuery.prototype添加一些函数集的对象的意义不大。因为我们new jQuery()是可以的,但是生成的jQuery对象在return时会被抛弃。所以最好不要用new jQuery()来构建jQuery对象。jQuery对象其实就是new jQuery.fn.init。那么jQuery.fn.init.prototype上就是挂着jQuery对象的操作方法。如

jQueryjQuery.fn.init.prototype = jQuery.fn;
有时间可能会担心在589行就实现了把jQuery.fn中的函数放到jQuery.fn.init.prototype上去,那么之后的通过 jQuery.fn.extend的方法怎么办呢?这里实际是对jQuery.fn的引用。在扩展jQuery的时候,只要把相关的函数extend到 jQuery.fn就可以了。现在我们看一下jQuery.fn.init是怎么完成工作的:

init : function(selector, context) { 
selectorselector = selector || document;// 确定selector存在 // 第一种情况 Handle $(DOMElement)单个Dom 元素,忽略上下文 
if (selector.nodeType) { 
this[0] = selector; 
this.length = 1; 
return this; 
} 
if (typeof selector == "string") {//selector为string 
var match = quickExpr.exec(selector); 
if (match && (match[1] || !context)) { 
if (match[1])// 第二种情况处理$(html) -> $(array) 
selector = jQuery.clean([match[1]], context); 
else {// 第三种情况:HANDLE: $("#id")//处理$("#id") 
var elem = document.getElementById(match[3]); 
if (elem) { 
// IE会返回name=id的元素 ,如果是这样,就document.find(s) 
if (elem.id != match[3]) 
return jQuery().find(selector); 
// 构建一个新的jQuery(elem) 
return jQuery(elem); 
} 
selector = []; 
} 
} else 
// 第四种情况:处理$(expr, [context])==$(content).find(expr) 
return jQuery(context).find(selector); 
} else if (jQuery.isFunction(selector)) // 第五种情况:处理$(function)七Shortcut for document ready 
return jQuery(document)[jQuery.fn.ready ? "ready" : "load"](selector); 
// 第六种情况:处理$(elements) 
return this.setArray(jQuery.makeArray(selector)); 
}
Javascript 相关文章推荐
IE下js调试工具Companion.JS
Oct 15 Javascript
JS的Document属性和方法小结
Sep 17 Javascript
JavaScript常用的返回,自动跳转,刷新,关闭语句汇总
Jan 13 Javascript
setinterval()与clearInterval()JS函数的调用方法
Jan 21 Javascript
第一次动手实现bootstrap table分页效果
Sep 22 Javascript
vue 实现 tomato timer(蕃茄钟)实例讲解
Jul 24 Javascript
jQuery-ui插件sortable实现自由拖动排序
Dec 01 jQuery
JavaScript动态检测密码强度原理及实现方法详解
Jun 11 Javascript
layui+jquery支持IE8的表格分页方法
Sep 28 jQuery
vue2.x 通过后端接口代理,获取qq音乐api的数据示例
Oct 30 Javascript
Js利用正则表达式去除字符串的中括号
Nov 23 Javascript
jQuery实现简单轮播图效果
Dec 27 jQuery
jQuery JSON的解析方式分享
Apr 05 #Javascript
jQuery 1.5 源码解读 面向中高阶JSER
Apr 05 #Javascript
基于jquery的动态创建表格的插件
Apr 05 #Javascript
基于jquery的合并table相同单元格的插件(精简版)
Apr 05 #Javascript
新鲜出炉的js tips提示效果
Apr 03 #Javascript
使用Firebug对js进行断点调试的图文方法
Apr 02 #Javascript
dreamweaver 安装Jquery智能提示
Apr 02 #Javascript
You might like
PHP使用strstr()函数获取指定字符串后所有字符的方法
2016/01/07 PHP
PHP数据库处理封装类实例
2016/12/24 PHP
php文件管理基本功能简单操作
2017/01/16 PHP
phpstudy默认不支持64位php的解决方法
2017/02/20 PHP
PHP实现的简单异常处理类示例
2017/05/04 PHP
PHP多进程简单实例小结
2019/11/09 PHP
ExtJS 2.2.1的grid控件在ie6中的显示问题
2009/05/04 Javascript
extjs grid设置某列背景颜色和字体颜色的方法
2010/09/03 Javascript
基于jquery的finkyUI插件与Ajax实现页面数据加载功能
2010/12/03 Javascript
jQuery 自定义函数写法分享
2012/03/30 Javascript
用javascript删除当前行,添加行(示例代码)
2013/11/25 Javascript
JavaScript面向对象的实现方法小结
2015/04/14 Javascript
jquery图片滚动放大代码分享(2)
2015/08/28 Javascript
js实现简单的计算器功能
2017/01/16 Javascript
详解vuex commit保存数据技巧
2018/12/25 Javascript
Easyui 关闭jquery-easui tab标签页前触发事件的解决方法
2019/04/28 jQuery
[01:20:38]完美世界DOTA2联赛 GXR vs IO 第一场 11.07
2020/11/09 DOTA
Python中的__SLOTS__属性使用示例
2015/02/18 Python
Python 爬虫模拟登陆知乎
2016/09/23 Python
简单易懂的python环境安装教程
2017/07/13 Python
virtualenv实现多个版本Python共存
2017/08/21 Python
python机器学习实战之K均值聚类
2017/12/20 Python
python爬取百度贴吧前1000页内容(requests库面向对象思想实现)
2019/08/10 Python
Python try except finally资源回收的实现
2021/01/25 Python
美国家具网站:Cymax
2016/09/17 全球购物
TripAdvisor土耳其网站:全球知名旅行社区,真实旅客评论
2017/04/17 全球购物
美国婴儿用品店:Babies”R”Us
2017/10/12 全球购物
实习生自我评价
2014/01/18 职场文书
文艺晚会主持词
2014/03/24 职场文书
公司大门门卫岗位职责
2014/06/11 职场文书
歌颂党的演讲稿
2014/09/10 职场文书
思想作风建设心得体会
2014/10/22 职场文书
爱岗敬业事迹材料
2014/12/24 职场文书
帝企鹅日记观后感
2015/06/10 职场文书
一文搞懂Python Sklearn库使用
2021/08/23 Python
JAVA API 实用类 String详解
2021/10/05 Java/Android