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 相关文章推荐
一些常用的Javascript函数
Dec 22 Javascript
js中cookie的使用详细分析
May 28 Javascript
JavaScript 产生不重复的随机数三种实现思路
Dec 13 Javascript
基于dom编程中 动态创建与删除元素的使用
Apr 17 Javascript
用javascript实现自动输出网页文本
Jul 30 Javascript
学习JavaScript设计模式之代理模式
Jan 12 Javascript
原生js编写autoComplete插件
Apr 13 Javascript
JavaScript编程中实现对象封装特性的实例讲解
Jun 24 Javascript
JavaScript简单验证表单空值及邮箱格式的方法
Jan 20 Javascript
jQuery实现淡入淡出的模态框
Feb 09 Javascript
vue组件父与子通信详解(一)
Nov 07 Javascript
原生js拖拽实现图形伸缩效果
Feb 10 Javascript
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开发模式(简写版)
2007/03/15 PHP
php学习笔记之 函数声明(二)
2011/06/09 PHP
使用gd库实现php服务端图片裁剪和生成缩略图功能分享
2013/12/25 PHP
使用laravel的Eloquent模型如何获取数据库的指定列
2019/10/17 PHP
this和执行上下文实现代码
2010/07/01 Javascript
js判断undefined变量类型使用typeof
2013/06/03 Javascript
JS Jquery 遍历,筛选页面元素 自动完成(实现代码)
2013/07/08 Javascript
jquery验证表单中的单选与多选实例
2013/08/18 Javascript
基于jQuery实现仿微博发布框字数提示
2016/07/27 Javascript
angularjs实现文字上下无缝滚动特效代码
2016/09/04 Javascript
AngularJS实现的select二级联动下拉菜单功能示例
2017/10/25 Javascript
详解weex默认webpack.config.js改造
2018/01/08 Javascript
使用webpack3.0配置webpack-dev-server教程
2018/05/29 Javascript
javascript实现支付宝滑块验证码效果
2020/07/24 Javascript
JavaScript的一些小技巧分享
2021/01/06 Javascript
[03:42]2018完美盛典-《加冕》
2018/12/16 DOTA
仅用500行Python代码实现一个英文解析器的教程
2015/04/02 Python
在Python的struct模块中进行数据格式转换的方法
2015/06/17 Python
Python的Flask框架应用调用Redis队列数据的方法
2016/06/06 Python
python中协程实现TCP连接的实例分析
2018/10/14 Python
Selenium定时刷新网页的实现代码
2018/10/31 Python
Python面向对象基础入门之设置对象属性
2018/12/11 Python
python写程序统计词频的方法
2019/07/29 Python
解决django同步数据库的时候app models表没有成功创建的问题
2019/08/09 Python
python pandas利用fillna方法实现部分自动填充功能
2020/03/16 Python
用python实现前向分词最大匹配算法的示例代码
2020/08/06 Python
Sperry澳大利亚官网:源自美国帆船鞋创始品牌
2019/07/29 全球购物
如果一个类实现了多个接口但是这些接口有相同的方法名将会怎样
2013/06/16 面试题
中学老师的自我评价
2013/11/07 职场文书
给校长的建议书500字
2014/05/15 职场文书
2014大学生职业生涯规划书最新范文
2014/09/13 职场文书
2014年政府采购工作总结
2014/12/09 职场文书
go结构体嵌套的切片数组操作
2021/04/28 Golang
动漫APP软件排行榜前十名,半次元上榜,第一款由腾讯公司推出
2022/03/18 杂记
python运行脚本文件的三种方法实例
2022/06/25 Python