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 相关文章推荐
pjblog中的UBBCode.js
Apr 25 Javascript
JavaScript Event学习第五章 高级事件注册模型
Feb 07 Javascript
dess中一个简单的多路委托的实现
Jul 20 Javascript
深入解析contentWindow, contentDocument
Jul 04 Javascript
iframe跨域通信封装详解
Aug 11 Javascript
详解如何构建Angular项目目录结构
Jul 13 Javascript
解决Vue在封装了Axios后手动刷新页面拦截器无效的问题
Nov 08 Javascript
Bootstrap实现省市区三级联动(亲测可用)
Jul 26 Javascript
axios如何利用promise无痛刷新token的实现方法
Aug 27 Javascript
在vue中使用Echarts利用watch做动态数据渲染操作
Jul 20 Javascript
Vue双向数据绑定(MVVM)的原理
Oct 03 Javascript
vue 插槽简介及使用示例
Nov 19 Vue.js
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
Re:从零开始的异世界生活 第2季 开播啦
2020/07/24 日漫
PHPnow安装服务[apache_pn]失败的问题的解决方法
2010/09/10 PHP
php使用exec shell命令注入的方法讲解
2013/11/12 PHP
Thinkphp调用Image类生成缩略图的方法
2015/03/07 PHP
PHP版本如何选择?应该使用哪个版本?
2015/05/13 PHP
thinkphp中AJAX返回ajaxReturn()方法分析
2016/12/06 PHP
php实现解析xml并生成sql语句的方法
2018/02/03 PHP
jquery引用方法时传递参数原理分析
2014/10/13 Javascript
angularJS与bootstrap结合实现动态加载弹出提示内容
2015/10/16 Javascript
jqueryMobile 动态添加元素,展示刷新视图的实现方法
2016/05/28 Javascript
JS使用单链表统计英语单词出现次数
2016/06/16 Javascript
Dropzone.js实现文件拖拽上传功能(附源码下载)
2016/11/22 Javascript
vue数组对象排序的实现代码
2018/06/20 Javascript
在Create React App中使用CSS Modules的方法示例
2019/01/15 Javascript
Nuxt.js 数据双向绑定的实现
2019/02/17 Javascript
JS学习笔记之闭包小案例分析
2019/05/29 Javascript
Layui给switch添加响应事件的例子
2019/09/03 Javascript
如何编写一个 Webpack Loader的实现
2020/10/18 Javascript
python实现获取客户机上指定文件并传输到服务器的方法
2015/03/16 Python
详解在Python程序中自定义异常的方法
2015/10/16 Python
简述Python中的进程、线程、协程
2016/03/18 Python
Python离线安装PIL 模块的方法
2019/01/08 Python
Python3.4学习笔记之 idle 清屏扩展插件用法分析
2019/03/01 Python
Python3.5以上版本lxml导入etree报错的解决方案
2019/06/26 Python
美国受欢迎的女性牛仔裤品牌:DL1961
2016/11/12 全球购物
C语言基础笔试题
2013/04/27 面试题
造价工程师个人求职信
2013/09/21 职场文书
建筑公司文秘岗位职责
2013/11/29 职场文书
学年末自我鉴定
2014/01/21 职场文书
家长会演讲稿
2014/04/26 职场文书
成绩单评语
2015/01/04 职场文书
销售员自我评价
2015/03/11 职场文书
python字符串的多行输出的实例详解
2021/06/08 Python
Win11怎样将锁屏账户头像图片改成动画视频
2021/11/21 数码科技
windows server 2016 域环境搭建的方法步骤(图文)
2022/06/25 Servers
JS前端可视化canvas动画原理及其推导实现
2022/08/05 Javascript